From 2d931ea68ee8c2c9474896e956279e55e5959ecf Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 24 Mar 2026 16:19:52 +0900 Subject: [PATCH 001/128] =?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=EA=B4=80=EB=A0=A8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9775dda0ae..5fbcb1d22a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ # java-janggi -장기 미션 저장소 +# 구현 기능 + +- 보드 초기화 + - 각 플레이어에게 장기판 차림 방법을 입력 받는다. + - 먼저 플레이하는 초나라부터 명령 번호를 입력하여 판차림 방법을 결정한다. + - 1, 2, 3, 4 이외의 숫자가 들어오는 경우 예외 처리한다. + - 선택할 수 있는 판차림은 다음과 같다. + 1. 왼상 차림 + 2. 오른상 차림 + 3. 안상 차림 + 4. 바깥상 차림 + - 입력한 장기판 차림을 기반으로 보드를 세팅한다. + - 보드 출력 + - 빈 공간은 온점 전각 문자를 활용한다. + - 팀 구분은 색상(빨강, 파랑)으로 구분한다. + - 기물은 각 기물에 대응하는 한나라의 한자로 표기한다. \ No newline at end of file From b841d4a67c5d2ac8a149bf0ba467aafa6a12bc4a Mon Sep 17 00:00:00 2001 From: EveryPine Date: Tue, 24 Mar 2026 19:44:02 +0900 Subject: [PATCH 002/128] =?UTF-8?q?test(setup-policy):=20=EC=9E=A5?= =?UTF-8?q?=EA=B8=B0=ED=8C=90=20=EC=B0=A8=EB=A6=BC=20=EC=A0=95=EC=B1=85=20?= =?UTF-8?q?=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 --- .../domain/InnerElephantSetupPolicyTest.java | 31 +++++++++++++++++++ .../domain/LeftElephantSetupPolicyTest.java | 31 +++++++++++++++++++ .../domain/OuterElephantSetupPolicyTest.java | 31 +++++++++++++++++++ .../domain/RightElephantSetupPolicyTest.java | 31 +++++++++++++++++++ .../fixture/SetupPolicyTestFixture.java | 26 ++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java create mode 100644 src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java create mode 100644 src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java create mode 100644 src/test/java/janggi/domain/RightElephantSetupPolicyTest.java create mode 100644 src/test/java/janggi/fixture/SetupPolicyTestFixture.java diff --git a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java b/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java new file mode 100644 index 0000000000..3da8960196 --- /dev/null +++ b/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java @@ -0,0 +1,31 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.fixture.SetupPolicyTestFixture; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.swing.text.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; + +class InnerElephantSetupPolicyTest { + + @ParameterizedTest + @DisplayName("안상 차림 테스트") + void setUp(List> s1) { + Map expected = + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + expected.put(Position.valueOf(1, 2), PieceType.HORSE); + expected.put(Position.valueOf(1, 3), PieceType.ELEPHANT); + expected.put(Position.valueOf(1, 7), PieceType.ELEPHANT); + expected.put(Position.valueOf(1, 8), PieceType.HORSE); + + Map actual = InnerElephantSetupPolicy.offerBoardMap(); + + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } +} diff --git a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java b/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java new file mode 100644 index 0000000000..087748878c --- /dev/null +++ b/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java @@ -0,0 +1,31 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.fixture.SetupPolicyTestFixture; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.swing.text.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; + +public class LeftElephantSetupPolicyTest { + + @ParameterizedTest + @DisplayName("왼상 차림 테스트") + void setUp(List> s1) { + Map expected = + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + expected.put(Position.valueOf(1, 2), PieceType.ELEPHANT); + expected.put(Position.valueOf(1, 3), PieceType.HORSE); + expected.put(Position.valueOf(1, 7), PieceType.ELEPHANT); + expected.put(Position.valueOf(1, 8), PieceType.HORSE); + + Map actual = InnerElephantSetupPolicy.offerBoardMap(); + + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } +} \ No newline at end of file diff --git a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java b/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java new file mode 100644 index 0000000000..ab28482098 --- /dev/null +++ b/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java @@ -0,0 +1,31 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.fixture.SetupPolicyTestFixture; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.swing.text.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; + +class OuterElephantSetupPolicyTest { + + @ParameterizedTest + @DisplayName("바깥상 차림 테스트") + void setUp(List> s1) { + Map expected = + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + expected.put(Position.valueOf(1, 2), PieceType.ELEPHANT); + expected.put(Position.valueOf(1, 3), PieceType.HORSE); + expected.put(Position.valueOf(1, 7), PieceType.HORSE); + expected.put(Position.valueOf(1, 8), PieceType.ELEPHANT); + + Map actual = InnerElephantSetupPolicy.offerBoardMap(); + + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } +} diff --git a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java b/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java new file mode 100644 index 0000000000..d2bb460f6e --- /dev/null +++ b/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java @@ -0,0 +1,31 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.fixture.SetupPolicyTestFixture; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.swing.text.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; + +class RightElephantSetupPolicyTest { + + @ParameterizedTest + @DisplayName("오른상 차림 테스트") + void setUp(List> s1) { + Map expected = + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + expected.put(Position.valueOf(1, 2), PieceType.HORSE); + expected.put(Position.valueOf(1, 3), PieceType.ELEPHANT); + expected.put(Position.valueOf(1, 7), PieceType.HORSE); + expected.put(Position.valueOf(1, 8), PieceType.ELEPHANT); + + Map actual = InnerElephantSetupPolicy.offerBoardMap(); + + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } +} \ No newline at end of file diff --git a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java b/src/test/java/janggi/fixture/SetupPolicyTestFixture.java new file mode 100644 index 0000000000..f18a7ff14e --- /dev/null +++ b/src/test/java/janggi/fixture/SetupPolicyTestFixture.java @@ -0,0 +1,26 @@ +package janggi.fixture; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Stream; +import javax.swing.text.Position; + +public class SetupPolicyTestFixture { + + public static Map 상_마를_제외한_기물_배치_정보_제공() { + return Stream.of( + Map.entry(Position.valueOf(1, 1), PieceType.CHARIOT), + Map.entry(Position.valueOf(1, 4), PieceType.GUARD), + Map.entry(Position.valueOf(1, 6), PieceType.GUARD), + Map.entry(Position.valueOf(1, 9), PieceType.CHARIOT), + Map.entry(Position.valueOf(2, 5), PieceType.GENERAL), + Map.entry(Position.valueOf(3, 2), PieceType.CANNON), + Map.entry(Position.valueOf(3, 8), PieceType.CANNON), + Map.entry(Position.valueOf(4, 1), PieceType.SOLDIER), + Map.entry(Position.valueOf(4, 3), PieceType.SOLDIER), + Map.entry(Position.valueOf(4, 5), PieceType.SOLDIER), + Map.entry(Position.valueOf(4, 7), PieceType.SOLDIER), + Map.entry(Position.valueOf(4, 9), PieceType.SOLDIER) + ); + } +} From d2caeba82d981ff351eb91db3e5a2310bf4de5b7 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 24 Mar 2026 20:45:29 +0900 Subject: [PATCH 003/128] =?UTF-8?q?feat(setup-policy):=20=EC=9E=A5?= =?UTF-8?q?=EA=B8=B0=ED=8C=90=20=EC=B0=A8=EB=A6=BC=20=EC=A0=95=EC=B1=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/InnerElephantSetupPolicy.java | 17 +++++++ .../domain/LeftElephantSetupPolicy.java | 16 ++++++ .../domain/OuterElephantSetupPolicy.java | 16 ++++++ src/main/java/janggi/domain/PieceType.java | 6 +++ src/main/java/janggi/domain/Position.java | 50 +++++++++++++++++++ .../domain/RightElephantSetupPolicy.java | 16 ++++++ src/main/java/janggi/domain/SetupPolicy.java | 26 ++++++++++ .../domain/InnerElephantSetupPolicyTest.java | 16 +++--- .../domain/LeftElephantSetupPolicyTest.java | 16 +++--- .../domain/OuterElephantSetupPolicyTest.java | 16 +++--- .../domain/RightElephantSetupPolicyTest.java | 16 +++--- .../fixture/SetupPolicyTestFixture.java | 34 ++++++------- 12 files changed, 192 insertions(+), 53 deletions(-) create mode 100644 src/main/java/janggi/domain/InnerElephantSetupPolicy.java create mode 100644 src/main/java/janggi/domain/LeftElephantSetupPolicy.java create mode 100644 src/main/java/janggi/domain/OuterElephantSetupPolicy.java create mode 100644 src/main/java/janggi/domain/PieceType.java create mode 100644 src/main/java/janggi/domain/Position.java create mode 100644 src/main/java/janggi/domain/RightElephantSetupPolicy.java create mode 100644 src/main/java/janggi/domain/SetupPolicy.java diff --git a/src/main/java/janggi/domain/InnerElephantSetupPolicy.java b/src/main/java/janggi/domain/InnerElephantSetupPolicy.java new file mode 100644 index 0000000000..027d8b7b29 --- /dev/null +++ b/src/main/java/janggi/domain/InnerElephantSetupPolicy.java @@ -0,0 +1,17 @@ +package janggi.domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class InnerElephantSetupPolicy extends SetupPolicy { + + @Override + public Map offerBoardMap() { + final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); + boardMap.put(Position.valueOf(1, 2), PieceType.HORSE); + boardMap.put(Position.valueOf(1, 3), PieceType.ELEPHANT); + boardMap.put(Position.valueOf(1, 7), PieceType.ELEPHANT); + boardMap.put(Position.valueOf(1, 8), PieceType.HORSE); + return boardMap; + } +} diff --git a/src/main/java/janggi/domain/LeftElephantSetupPolicy.java b/src/main/java/janggi/domain/LeftElephantSetupPolicy.java new file mode 100644 index 0000000000..54c6b0baac --- /dev/null +++ b/src/main/java/janggi/domain/LeftElephantSetupPolicy.java @@ -0,0 +1,16 @@ +package janggi.domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class LeftElephantSetupPolicy extends SetupPolicy { + @Override + public Map offerBoardMap() { + final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); + boardMap.put(Position.valueOf(1, 2), PieceType.ELEPHANT); + boardMap.put(Position.valueOf(1, 3), PieceType.HORSE); + boardMap.put(Position.valueOf(1, 7), PieceType.ELEPHANT); + boardMap.put(Position.valueOf(1, 8), PieceType.HORSE); + return boardMap; + } +} diff --git a/src/main/java/janggi/domain/OuterElephantSetupPolicy.java b/src/main/java/janggi/domain/OuterElephantSetupPolicy.java new file mode 100644 index 0000000000..70f986b961 --- /dev/null +++ b/src/main/java/janggi/domain/OuterElephantSetupPolicy.java @@ -0,0 +1,16 @@ +package janggi.domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class OuterElephantSetupPolicy extends SetupPolicy { + @Override + public Map offerBoardMap() { + final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); + boardMap.put(Position.valueOf(1, 2), PieceType.ELEPHANT); + boardMap.put(Position.valueOf(1, 3), PieceType.HORSE); + boardMap.put(Position.valueOf(1, 7), PieceType.HORSE); + boardMap.put(Position.valueOf(1, 8), PieceType.ELEPHANT); + return boardMap; + } +} diff --git a/src/main/java/janggi/domain/PieceType.java b/src/main/java/janggi/domain/PieceType.java new file mode 100644 index 0000000000..679679ed9c --- /dev/null +++ b/src/main/java/janggi/domain/PieceType.java @@ -0,0 +1,6 @@ +package janggi.domain; + +public enum PieceType { + GENERAL, GUARD, HORSE, ELEPHANT, CHARIOT, CANNON, SOLDIER + +} diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java new file mode 100644 index 0000000000..5e478a1e30 --- /dev/null +++ b/src/main/java/janggi/domain/Position.java @@ -0,0 +1,50 @@ +package janggi.domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Position { + + private static final int MAXIMUM_ROW = 10; + private static final int MAXIMUM_COLUMN = 9; + private static final int MINIMUM_ROW = 1; + private static final int MINIMUM_COLUMN = 1; + private static final Map> CACHE; + + static { + CACHE = new LinkedHashMap<>(); + for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { + CACHE.put(row, new LinkedHashMap<>()); + } + } + + private final int row; + private final int column; + + private Position(final int row, final int column) { + validateRowRange(row); + validateColumnRange(column); + this.row = row; + this.column = column; + } + + public static Position valueOf(final int row, final int column) { + final Map secondaryMap = CACHE.get(row); + if (!secondaryMap.containsKey(column)) { + secondaryMap.put(column, new Position(row, column)); + } + return secondaryMap.get(column); + } + + private void validateRowRange(final int row) { + if (row < MINIMUM_ROW || row > MAXIMUM_ROW) { + throw new IllegalArgumentException("행 입력은 1~10을 입력해야 합니다."); + } + } + + private void validateColumnRange(final int column) { + if (column < MINIMUM_COLUMN || column > MAXIMUM_COLUMN) { + throw new IllegalArgumentException("열 입력은 1~9을 입력해야 합니다."); + } + } +} diff --git a/src/main/java/janggi/domain/RightElephantSetupPolicy.java b/src/main/java/janggi/domain/RightElephantSetupPolicy.java new file mode 100644 index 0000000000..98b7755098 --- /dev/null +++ b/src/main/java/janggi/domain/RightElephantSetupPolicy.java @@ -0,0 +1,16 @@ +package janggi.domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class RightElephantSetupPolicy extends SetupPolicy { + @Override + public Map offerBoardMap() { + final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); + boardMap.put(Position.valueOf(1, 2), PieceType.HORSE); + boardMap.put(Position.valueOf(1, 3), PieceType.ELEPHANT); + boardMap.put(Position.valueOf(1, 7), PieceType.HORSE); + boardMap.put(Position.valueOf(1, 8), PieceType.ELEPHANT); + return boardMap; + } +} diff --git a/src/main/java/janggi/domain/SetupPolicy.java b/src/main/java/janggi/domain/SetupPolicy.java new file mode 100644 index 0000000000..39417ab2a5 --- /dev/null +++ b/src/main/java/janggi/domain/SetupPolicy.java @@ -0,0 +1,26 @@ +package janggi.domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public abstract class SetupPolicy { + static final Map COMMON_BOARD_MAP; + + static { + COMMON_BOARD_MAP = new LinkedHashMap<>(); + COMMON_BOARD_MAP.put(Position.valueOf(1, 1), PieceType.CHARIOT); + COMMON_BOARD_MAP.put(Position.valueOf(1, 4), PieceType.GUARD); + COMMON_BOARD_MAP.put(Position.valueOf(1, 6), PieceType.GUARD); + COMMON_BOARD_MAP.put(Position.valueOf(1, 9), PieceType.CHARIOT); + COMMON_BOARD_MAP.put(Position.valueOf(2, 5), PieceType.GENERAL); + COMMON_BOARD_MAP.put(Position.valueOf(3, 2), PieceType.CANNON); + COMMON_BOARD_MAP.put(Position.valueOf(3, 8), PieceType.CANNON); + COMMON_BOARD_MAP.put(Position.valueOf(4, 1), PieceType.SOLDIER); + COMMON_BOARD_MAP.put(Position.valueOf(4, 3), PieceType.SOLDIER); + COMMON_BOARD_MAP.put(Position.valueOf(4, 5), PieceType.SOLDIER); + COMMON_BOARD_MAP.put(Position.valueOf(4, 7), PieceType.SOLDIER); + COMMON_BOARD_MAP.put(Position.valueOf(4, 9), PieceType.SOLDIER); + } + + public abstract Map offerBoardMap(); +} \ No newline at end of file diff --git a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java b/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java index 3da8960196..538fd8dc31 100644 --- a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java @@ -4,28 +4,26 @@ import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import javax.swing.text.Position; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.api.Test; class InnerElephantSetupPolicyTest { - @ParameterizedTest + @Test @DisplayName("안상 차림 테스트") - void setUp(List> s1) { + void setUp() { + InnerElephantSetupPolicy policy = new InnerElephantSetupPolicy(); Map expected = - new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.HORSE); expected.put(Position.valueOf(1, 3), PieceType.ELEPHANT); expected.put(Position.valueOf(1, 7), PieceType.ELEPHANT); expected.put(Position.valueOf(1, 8), PieceType.HORSE); - Map actual = InnerElephantSetupPolicy.offerBoardMap(); + Map actual = policy.offerBoardMap(); assertThat(actual).usingRecursiveComparison() - .isEqualTo(expected); + .isEqualTo(expected); } } diff --git a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java b/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java index 087748878c..752fa4b613 100644 --- a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java @@ -4,28 +4,26 @@ import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import javax.swing.text.Position; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.api.Test; public class LeftElephantSetupPolicyTest { - @ParameterizedTest + @Test @DisplayName("왼상 차림 테스트") - void setUp(List> s1) { + void setUp() { + LeftElephantSetupPolicy policy = new LeftElephantSetupPolicy(); Map expected = - new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.ELEPHANT); expected.put(Position.valueOf(1, 3), PieceType.HORSE); expected.put(Position.valueOf(1, 7), PieceType.ELEPHANT); expected.put(Position.valueOf(1, 8), PieceType.HORSE); - Map actual = InnerElephantSetupPolicy.offerBoardMap(); + Map actual = policy.offerBoardMap(); assertThat(actual).usingRecursiveComparison() - .isEqualTo(expected); + .isEqualTo(expected); } } \ No newline at end of file diff --git a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java b/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java index ab28482098..3de58f55d5 100644 --- a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java @@ -4,28 +4,26 @@ import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import javax.swing.text.Position; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.api.Test; class OuterElephantSetupPolicyTest { - @ParameterizedTest + @Test @DisplayName("바깥상 차림 테스트") - void setUp(List> s1) { + void setUp() { + OuterElephantSetupPolicy policy = new OuterElephantSetupPolicy(); Map expected = - new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.ELEPHANT); expected.put(Position.valueOf(1, 3), PieceType.HORSE); expected.put(Position.valueOf(1, 7), PieceType.HORSE); expected.put(Position.valueOf(1, 8), PieceType.ELEPHANT); - Map actual = InnerElephantSetupPolicy.offerBoardMap(); + Map actual = policy.offerBoardMap(); assertThat(actual).usingRecursiveComparison() - .isEqualTo(expected); + .isEqualTo(expected); } } diff --git a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java b/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java index d2bb460f6e..135e999b06 100644 --- a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java @@ -4,28 +4,26 @@ import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import javax.swing.text.Position; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.api.Test; class RightElephantSetupPolicyTest { - @ParameterizedTest + @Test @DisplayName("오른상 차림 테스트") - void setUp(List> s1) { + void setUp() { + RightElephantSetupPolicy policy = new RightElephantSetupPolicy(); Map expected = - new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); + new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.HORSE); expected.put(Position.valueOf(1, 3), PieceType.ELEPHANT); expected.put(Position.valueOf(1, 7), PieceType.HORSE); expected.put(Position.valueOf(1, 8), PieceType.ELEPHANT); - Map actual = InnerElephantSetupPolicy.offerBoardMap(); + Map actual = policy.offerBoardMap(); assertThat(actual).usingRecursiveComparison() - .isEqualTo(expected); + .isEqualTo(expected); } } \ No newline at end of file diff --git a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java b/src/test/java/janggi/fixture/SetupPolicyTestFixture.java index f18a7ff14e..afda1c6d0f 100644 --- a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java +++ b/src/test/java/janggi/fixture/SetupPolicyTestFixture.java @@ -1,26 +1,26 @@ package janggi.fixture; +import janggi.domain.PieceType; +import janggi.domain.Position; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Stream; -import javax.swing.text.Position; public class SetupPolicyTestFixture { public static Map 상_마를_제외한_기물_배치_정보_제공() { - return Stream.of( - Map.entry(Position.valueOf(1, 1), PieceType.CHARIOT), - Map.entry(Position.valueOf(1, 4), PieceType.GUARD), - Map.entry(Position.valueOf(1, 6), PieceType.GUARD), - Map.entry(Position.valueOf(1, 9), PieceType.CHARIOT), - Map.entry(Position.valueOf(2, 5), PieceType.GENERAL), - Map.entry(Position.valueOf(3, 2), PieceType.CANNON), - Map.entry(Position.valueOf(3, 8), PieceType.CANNON), - Map.entry(Position.valueOf(4, 1), PieceType.SOLDIER), - Map.entry(Position.valueOf(4, 3), PieceType.SOLDIER), - Map.entry(Position.valueOf(4, 5), PieceType.SOLDIER), - Map.entry(Position.valueOf(4, 7), PieceType.SOLDIER), - Map.entry(Position.valueOf(4, 9), PieceType.SOLDIER) - ); + Map map = new LinkedHashMap<>(); + map.put(Position.valueOf(1, 1), PieceType.CHARIOT); + map.put(Position.valueOf(1, 4), PieceType.GUARD); + map.put(Position.valueOf(1, 6), PieceType.GUARD); + map.put(Position.valueOf(1, 9), PieceType.CHARIOT); + map.put(Position.valueOf(2, 5), PieceType.GENERAL); + map.put(Position.valueOf(3, 2), PieceType.CANNON); + map.put(Position.valueOf(3, 8), PieceType.CANNON); + map.put(Position.valueOf(4, 1), PieceType.SOLDIER); + map.put(Position.valueOf(4, 3), PieceType.SOLDIER); + map.put(Position.valueOf(4, 5), PieceType.SOLDIER); + map.put(Position.valueOf(4, 7), PieceType.SOLDIER); + map.put(Position.valueOf(4, 9), PieceType.SOLDIER); + return map; } } From d1e853cfbf9aa9e48d51bca312f26b9476c69834 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Wed, 25 Mar 2026 10:55:50 +0900 Subject: [PATCH 004/128] =?UTF-8?q?test(setup-command):=20=EC=B0=A8?= =?UTF-8?q?=EB=A6=BC=ED=8C=90=20=EB=AA=85=EB=A0=B9=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 --- .../java/janggi/domain/SetupCommandTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/java/janggi/domain/SetupCommandTest.java diff --git a/src/test/java/janggi/domain/SetupCommandTest.java b/src/test/java/janggi/domain/SetupCommandTest.java new file mode 100644 index 0000000000..2e044f30ba --- /dev/null +++ b/src/test/java/janggi/domain/SetupCommandTest.java @@ -0,0 +1,17 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class SetupCommandTest { + + @Test + @DisplayName("차림판 예외 테스트") + void normalInputTest() { + int wrongNumber = 5; + assertThatIllegalArgumentException() + .isThrownBy(() -> new SetupCommand(wrongNumber)); + } +} From 04f9dc61ca622edc138ce6a1b16cbe561eb3f494 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 11:04:59 +0900 Subject: [PATCH 005/128] =?UTF-8?q?feat(setup-command):=20=EC=B0=A8?= =?UTF-8?q?=EB=A6=BC=20=EB=AA=85=EB=A0=B9=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/command/SetupCommand.java | 28 +++++++++++++++++++ .../java/janggi/domain/SetupCommandTest.java | 5 ++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/main/java/janggi/domain/command/SetupCommand.java diff --git a/src/main/java/janggi/domain/command/SetupCommand.java b/src/main/java/janggi/domain/command/SetupCommand.java new file mode 100644 index 0000000000..5152771aee --- /dev/null +++ b/src/main/java/janggi/domain/command/SetupCommand.java @@ -0,0 +1,28 @@ +package janggi.domain.command; + +import java.util.Arrays; + +public enum SetupCommand { + + INNER_ELEPHANT(1), + OUTER_ELEPHANT(2), + LEFT_ELEPHANT(3), + RIGHT_ELEPHANT(4); + + private static final int MINUMUM_NUMBER = 1; + private static final int MAXIMUM_NUMBER = 4; + + private final int number; + + SetupCommand(final int number) { + this.number = number; + } + + public static SetupCommand pick(final int number) { + return Arrays.stream(values()) + .filter(setupCommand -> setupCommand.number == number) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format( + "명령 번호는 %d에서 %d까지의 정수 값이어야 합니다.", MINUMUM_NUMBER, MAXIMUM_NUMBER))); + } +} diff --git a/src/test/java/janggi/domain/SetupCommandTest.java b/src/test/java/janggi/domain/SetupCommandTest.java index 2e044f30ba..442e704f9e 100644 --- a/src/test/java/janggi/domain/SetupCommandTest.java +++ b/src/test/java/janggi/domain/SetupCommandTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import janggi.domain.command.SetupCommand; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -9,9 +10,9 @@ public class SetupCommandTest { @Test @DisplayName("차림판 예외 테스트") - void normalInputTest() { + void failure() { int wrongNumber = 5; assertThatIllegalArgumentException() - .isThrownBy(() -> new SetupCommand(wrongNumber)); + .isThrownBy(() -> SetupCommand.pick(wrongNumber)); } } From 96236d6355a39b4cbd1b22abcdbf1402e9632c20 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Wed, 25 Mar 2026 11:17:43 +0900 Subject: [PATCH 006/128] =?UTF-8?q?test(board-generator):=20=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=ED=8C=90=20=EA=B8=B0=EB=AC=BC=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/BoardGeneratorTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/java/janggi/domain/BoardGeneratorTest.java diff --git a/src/test/java/janggi/domain/BoardGeneratorTest.java b/src/test/java/janggi/domain/BoardGeneratorTest.java new file mode 100644 index 0000000000..ba2d30579e --- /dev/null +++ b/src/test/java/janggi/domain/BoardGeneratorTest.java @@ -0,0 +1,23 @@ +package janggi.domain; + +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class BoardGeneratorTest { + + @Test + @DisplayName("보드판 기물 정상 테스트") + void success() { + // given + final int expected = 32; + + // when + Board board = BoardGenerator.generate(new InnerElephantSetupPolicy()); + + // then + assertThat(board).extracting("positionPieceMap") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .hasSize(expected); + } +} From 703c6ccdf086ed21cb52cd9e14b041ce3281ad69 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 13:36:05 +0900 Subject: [PATCH 007/128] =?UTF-8?q?feat(board-generator):=20=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=ED=8C=90=20=EA=B8=B0=EB=AC=BC=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/PieceType.java | 32 +++++++++++++++++-- src/main/java/janggi/domain/Position.java | 5 +++ src/main/java/janggi/domain/board/Board.java | 16 ++++++++++ .../janggi/domain/board/BoardGenerator.java | 22 +++++++++++++ src/main/java/janggi/domain/piece/Cannon.java | 15 +++++++++ .../java/janggi/domain/piece/Chariot.java | 16 ++++++++++ .../java/janggi/domain/piece/Elephant.java | 15 +++++++++ .../java/janggi/domain/piece/General.java | 15 +++++++++ src/main/java/janggi/domain/piece/Guard.java | 15 +++++++++ src/main/java/janggi/domain/piece/Horse.java | 15 +++++++++ src/main/java/janggi/domain/piece/Piece.java | 5 +++ .../java/janggi/domain/piece/Soldier.java | 13 ++++++++ .../java/janggi/domain/team/BlueTeam.java | 28 ++++++++++++++++ src/main/java/janggi/domain/team/RedTeam.java | 29 +++++++++++++++++ src/main/java/janggi/domain/team/Team.java | 9 ++++++ .../java/janggi/domain/team/TeamType.java | 5 +++ .../janggi/domain/BoardGeneratorTest.java | 10 +++++- 17 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 src/main/java/janggi/domain/board/Board.java create mode 100644 src/main/java/janggi/domain/board/BoardGenerator.java create mode 100644 src/main/java/janggi/domain/piece/Cannon.java create mode 100644 src/main/java/janggi/domain/piece/Chariot.java create mode 100644 src/main/java/janggi/domain/piece/Elephant.java create mode 100644 src/main/java/janggi/domain/piece/General.java create mode 100644 src/main/java/janggi/domain/piece/Guard.java create mode 100644 src/main/java/janggi/domain/piece/Horse.java create mode 100644 src/main/java/janggi/domain/piece/Piece.java create mode 100644 src/main/java/janggi/domain/piece/Soldier.java create mode 100644 src/main/java/janggi/domain/team/BlueTeam.java create mode 100644 src/main/java/janggi/domain/team/RedTeam.java create mode 100644 src/main/java/janggi/domain/team/Team.java create mode 100644 src/main/java/janggi/domain/team/TeamType.java diff --git a/src/main/java/janggi/domain/PieceType.java b/src/main/java/janggi/domain/PieceType.java index 679679ed9c..f72c175612 100644 --- a/src/main/java/janggi/domain/PieceType.java +++ b/src/main/java/janggi/domain/PieceType.java @@ -1,6 +1,34 @@ package janggi.domain; +import janggi.domain.piece.Cannon; +import janggi.domain.piece.Chariot; +import janggi.domain.piece.Elephant; +import janggi.domain.piece.General; +import janggi.domain.piece.Guard; +import janggi.domain.piece.Horse; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.function.Function; + public enum PieceType { - GENERAL, GUARD, HORSE, ELEPHANT, CHARIOT, CANNON, SOLDIER - + + GENERAL(General::new), + GUARD(Guard::new), + HORSE(Horse::new), + ELEPHANT(Elephant::new), + CHARIOT(Chariot::new), + CANNON(Cannon::new), + SOLDIER(Soldier::new); + + private final Function function; + + PieceType(Function function) { + this.function = function; + } + + public Piece toPiece(final TeamType teamType) { + return function.apply(teamType); + } + } diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 5e478a1e30..6bc95a4317 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -9,6 +9,7 @@ public final class Position { private static final int MAXIMUM_COLUMN = 9; private static final int MINIMUM_ROW = 1; private static final int MINIMUM_COLUMN = 1; + private static final int ROW_FLIP_VALUE = 11; private static final Map> CACHE; static { @@ -36,6 +37,10 @@ public static Position valueOf(final int row, final int column) { return secondaryMap.get(column); } + public Position flipAroundMiddleRow() { + return Position.valueOf(ROW_FLIP_VALUE - row, column); + } + private void validateRowRange(final int row) { if (row < MINIMUM_ROW || row > MAXIMUM_ROW) { throw new IllegalArgumentException("행 입력은 1~10을 입력해야 합니다."); diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java new file mode 100644 index 0000000000..b051f2bd69 --- /dev/null +++ b/src/main/java/janggi/domain/board/Board.java @@ -0,0 +1,16 @@ +package janggi.domain.board; + +import janggi.domain.Position; +import janggi.domain.piece.Piece; +import java.util.Map; + +public class Board { + + private final Map positionPieceMap; + + public Board(final Map positionPieceMap) { + this.positionPieceMap = positionPieceMap; + } + + +} diff --git a/src/main/java/janggi/domain/board/BoardGenerator.java b/src/main/java/janggi/domain/board/BoardGenerator.java new file mode 100644 index 0000000000..1f7e312e0d --- /dev/null +++ b/src/main/java/janggi/domain/board/BoardGenerator.java @@ -0,0 +1,22 @@ +package janggi.domain.board; + +import janggi.domain.Position; +import janggi.domain.team.Team; +import janggi.domain.piece.Piece; +import java.util.LinkedHashMap; +import java.util.Map; + +public final class BoardGenerator { + + private BoardGenerator() { + + } + + public static Board generate(final Team redTeam, final Team blueTeam) { + final Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.putAll(redTeam.generatePieces()); + positionPieceMap.putAll(blueTeam.generatePieces()); + + return new Board(positionPieceMap); + } +} diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java new file mode 100644 index 0000000000..baa27ab851 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -0,0 +1,15 @@ +package janggi.domain.piece; + +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; + +public class Cannon implements Piece { + + private static final PieceType PIECE_TYPE = PieceType.CANNON; + + private final TeamType teamType; + + public Cannon(final TeamType teamType) { + this.teamType = teamType; + } +} diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java new file mode 100644 index 0000000000..113e341b97 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -0,0 +1,16 @@ +package janggi.domain.piece; + +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; + +public class Chariot implements Piece { + + private static final PieceType PIECE_TYPE = PieceType.CHARIOT; + + private final TeamType teamType; + + public Chariot(final TeamType teamType) { + this.teamType = teamType; + } + +} diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java new file mode 100644 index 0000000000..3e4ba71bf7 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -0,0 +1,15 @@ +package janggi.domain.piece; + +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; + +public class Elephant implements Piece { + + private static final PieceType PIECE_TYPE = PieceType.ELEPHANT; + + private final TeamType teamType; + + public Elephant(final TeamType teamType) { + this.teamType = teamType; + } +} diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java new file mode 100644 index 0000000000..c89217a373 --- /dev/null +++ b/src/main/java/janggi/domain/piece/General.java @@ -0,0 +1,15 @@ +package janggi.domain.piece; + +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; + +public class General implements Piece { + + private static final PieceType PIECE_TYPE = PieceType.GENERAL; + + private final TeamType teamType; + + public General(final TeamType teamType) { + this.teamType = teamType; + } +} diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java new file mode 100644 index 0000000000..14975a3a38 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -0,0 +1,15 @@ +package janggi.domain.piece; + +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; + +public class Guard implements Piece{ + + private static final PieceType PIECE_TYPE = PieceType.GUARD; + + private final TeamType teamType; + + public Guard(final TeamType teamType) { + this.teamType = teamType; + } +} diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java new file mode 100644 index 0000000000..2adbdd8010 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -0,0 +1,15 @@ +package janggi.domain.piece; + +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; + +public class Horse implements Piece { + + private static final PieceType PIECE_TYPE = PieceType.HORSE; + + private final TeamType teamType; + + public Horse(final TeamType teamType) { + this.teamType = teamType; + } +} diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java new file mode 100644 index 0000000000..1940c72c84 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -0,0 +1,5 @@ +package janggi.domain.piece; + +public interface Piece { + +} diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java new file mode 100644 index 0000000000..57c7f37a38 --- /dev/null +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -0,0 +1,13 @@ +package janggi.domain.piece; + +import janggi.domain.team.TeamType; + +public class Soldier implements Piece{ + + private final TeamType teamType; + + public Soldier(final TeamType teamType) { + this.teamType = teamType; + } + +} diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java new file mode 100644 index 0000000000..dfa17854db --- /dev/null +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -0,0 +1,28 @@ +package janggi.domain.team; + +import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.SetupPolicy; +import janggi.domain.piece.Piece; +import java.util.LinkedHashMap; +import java.util.Map; + +public class BlueTeam implements Team { + + private static final TeamType TEAM_TYPE = TeamType.BLUE; + private final SetupPolicy setupPolicy; + + public BlueTeam(final SetupPolicy setupPolicy) { + this.setupPolicy = setupPolicy; + } + + @Override + public Map generatePieces() { + final Map positionPieceMap = new LinkedHashMap<>(); + final Map positionPieceTypeMap = setupPolicy.offerBoardMap(); + positionPieceTypeMap.forEach((position, pieceType) -> + positionPieceMap.put(position.flipAroundMiddleRow(), pieceType.toPiece(TEAM_TYPE))); + + return positionPieceMap; + } +} diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java new file mode 100644 index 0000000000..7384eaad43 --- /dev/null +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -0,0 +1,29 @@ +package janggi.domain.team; + +import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.SetupPolicy; +import janggi.domain.piece.Piece; +import java.util.LinkedHashMap; +import java.util.Map; + +public class RedTeam implements Team { + + private static final TeamType TEAM_TYPE = TeamType.RED; + private final SetupPolicy setupPolicy; + + + public RedTeam(final SetupPolicy setupPolicy) { + this.setupPolicy = setupPolicy; + } + + @Override + public Map generatePieces() { + final Map positionPieceMap = new LinkedHashMap<>(); + final Map positionPieceTypeMap = setupPolicy.offerBoardMap(); + positionPieceTypeMap.forEach((position, pieceType) -> + positionPieceMap.put(position, pieceType.toPiece(TEAM_TYPE))); + + return positionPieceMap; + } +} diff --git a/src/main/java/janggi/domain/team/Team.java b/src/main/java/janggi/domain/team/Team.java new file mode 100644 index 0000000000..53c942c029 --- /dev/null +++ b/src/main/java/janggi/domain/team/Team.java @@ -0,0 +1,9 @@ +package janggi.domain.team; + +import janggi.domain.Position; +import janggi.domain.piece.Piece; +import java.util.Map; + +public interface Team { + Map generatePieces(); +} diff --git a/src/main/java/janggi/domain/team/TeamType.java b/src/main/java/janggi/domain/team/TeamType.java new file mode 100644 index 0000000000..f8b601200f --- /dev/null +++ b/src/main/java/janggi/domain/team/TeamType.java @@ -0,0 +1,5 @@ +package janggi.domain.team; + +public enum TeamType { + RED, BLUE; +} diff --git a/src/test/java/janggi/domain/BoardGeneratorTest.java b/src/test/java/janggi/domain/BoardGeneratorTest.java index ba2d30579e..c1ed295bf8 100644 --- a/src/test/java/janggi/domain/BoardGeneratorTest.java +++ b/src/test/java/janggi/domain/BoardGeneratorTest.java @@ -1,5 +1,11 @@ package janggi.domain; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardGenerator; +import janggi.domain.team.BlueTeam; +import janggi.domain.team.RedTeam; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -10,10 +16,12 @@ public class BoardGeneratorTest { @DisplayName("보드판 기물 정상 테스트") void success() { // given + RedTeam redTeam = new RedTeam(new InnerElephantSetupPolicy()); + BlueTeam blueTeam = new BlueTeam(new InnerElephantSetupPolicy()); final int expected = 32; // when - Board board = BoardGenerator.generate(new InnerElephantSetupPolicy()); + Board board = BoardGenerator.generate(redTeam, blueTeam); // then assertThat(board).extracting("positionPieceMap") From 283a7089f9e3668ed7adf6022cc5106b003a3144 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Wed, 25 Mar 2026 14:57:46 +0900 Subject: [PATCH 008/128] =?UTF-8?q?feat(view):=20=ED=8C=80=EB=B3=84=20?= =?UTF-8?q?=EC=B0=A8=EB=A6=BC=EB=B2=95=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/controller/JanggiController.java | 43 +++++++++++++++++++ src/main/java/janggi/domain/PieceType.java | 2 +- .../janggi/domain/command/SetupCommand.java | 40 +++++++++++++---- .../java/janggi/domain/team/BlueTeam.java | 7 ++- src/main/java/janggi/domain/team/RedTeam.java | 9 +++- src/main/java/janggi/domain/team/Team.java | 2 + .../java/janggi/domain/team/TeamType.java | 13 +++++- src/main/java/janggi/utils/Parser.java | 15 +++++++ src/main/java/janggi/utils/RetryExecutor.java | 18 ++++++++ src/main/java/janggi/view/InputView.java | 13 ++++++ src/main/java/janggi/view/OutputView.java | 22 ++++++++++ src/main/java/janggi/view/reader/Console.java | 17 ++++++++ 12 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 src/main/java/janggi/controller/JanggiController.java create mode 100644 src/main/java/janggi/utils/Parser.java create mode 100644 src/main/java/janggi/utils/RetryExecutor.java create mode 100644 src/main/java/janggi/view/InputView.java create mode 100644 src/main/java/janggi/view/OutputView.java create mode 100644 src/main/java/janggi/view/reader/Console.java diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java new file mode 100644 index 0000000000..761268dbdf --- /dev/null +++ b/src/main/java/janggi/controller/JanggiController.java @@ -0,0 +1,43 @@ +package janggi.controller; + +import janggi.domain.SetupPolicy; +import janggi.domain.board.Board; +import janggi.domain.board.BoardGenerator; +import janggi.domain.command.SetupCommand; +import janggi.domain.team.BlueTeam; +import janggi.domain.team.RedTeam; +import janggi.domain.team.Team; +import janggi.domain.team.TeamType; +import janggi.utils.RetryExecutor; +import janggi.view.InputView; +import janggi.view.OutputView; + +public class JanggiController { + public JanggiController() { + } + + private Team setupRedTeam() { + OutputView.printSetupGuide(TeamType.RED); + final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); + final SetupPolicy setupPolicy = setupCommand.toPolicy(); + return new RedTeam(setupPolicy); + } + + private Team setupBlueTeam() { + OutputView.printSetupGuide(TeamType.BLUE); + final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); + final SetupPolicy setupPolicy = setupCommand.toPolicy(); + return new BlueTeam(setupPolicy); + } + + public void run() { + Team redTeam = setupRedTeam(); + Team blueTeam = setupBlueTeam(); + Board board = BoardGenerator.generate(redTeam, blueTeam); + } + + private SetupCommand readSetupCommand() { + int commandNumber = InputView.readSetupCommand(); + return SetupCommand.pick(commandNumber); + } +} diff --git a/src/main/java/janggi/domain/PieceType.java b/src/main/java/janggi/domain/PieceType.java index f72c175612..b55d049a5a 100644 --- a/src/main/java/janggi/domain/PieceType.java +++ b/src/main/java/janggi/domain/PieceType.java @@ -22,7 +22,7 @@ public enum PieceType { SOLDIER(Soldier::new); private final Function function; - + PieceType(Function function) { this.function = function; } diff --git a/src/main/java/janggi/domain/command/SetupCommand.java b/src/main/java/janggi/domain/command/SetupCommand.java index 5152771aee..600d7607d7 100644 --- a/src/main/java/janggi/domain/command/SetupCommand.java +++ b/src/main/java/janggi/domain/command/SetupCommand.java @@ -1,28 +1,50 @@ package janggi.domain.command; +import janggi.domain.InnerElephantSetupPolicy; +import janggi.domain.LeftElephantSetupPolicy; +import janggi.domain.OuterElephantSetupPolicy; +import janggi.domain.RightElephantSetupPolicy; +import janggi.domain.SetupPolicy; import java.util.Arrays; +import java.util.function.Supplier; public enum SetupCommand { - INNER_ELEPHANT(1), - OUTER_ELEPHANT(2), - LEFT_ELEPHANT(3), - RIGHT_ELEPHANT(4); + INNER_ELEPHANT(1, "안상 차림", InnerElephantSetupPolicy::new), + OUTER_ELEPHANT(2, "바깥상 차림", OuterElephantSetupPolicy::new), + LEFT_ELEPHANT(3, "왼상 차림", LeftElephantSetupPolicy::new), + RIGHT_ELEPHANT(4, "오른상 차림", RightElephantSetupPolicy::new); private static final int MINUMUM_NUMBER = 1; private static final int MAXIMUM_NUMBER = 4; private final int number; + private final String description; + private final Supplier policySupplier; - SetupCommand(final int number) { + SetupCommand(final int number, final String description, final Supplier setupPolicySupplier) { this.number = number; + this.description = description; + this.policySupplier = setupPolicySupplier; } public static SetupCommand pick(final int number) { return Arrays.stream(values()) - .filter(setupCommand -> setupCommand.number == number) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException(String.format( - "명령 번호는 %d에서 %d까지의 정수 값이어야 합니다.", MINUMUM_NUMBER, MAXIMUM_NUMBER))); + .filter(setupCommand -> setupCommand.number == number) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format( + "명령 번호는 %d에서 %d까지의 정수 값이어야 합니다.", MINUMUM_NUMBER, MAXIMUM_NUMBER))); + } + + public SetupPolicy toPolicy() { + return policySupplier.get(); + } + + public int getNumber() { + return number; + } + + public String getDescription() { + return description; } } diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java index dfa17854db..81920d5b45 100644 --- a/src/main/java/janggi/domain/team/BlueTeam.java +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -21,8 +21,13 @@ public Map generatePieces() { final Map positionPieceMap = new LinkedHashMap<>(); final Map positionPieceTypeMap = setupPolicy.offerBoardMap(); positionPieceTypeMap.forEach((position, pieceType) -> - positionPieceMap.put(position.flipAroundMiddleRow(), pieceType.toPiece(TEAM_TYPE))); + positionPieceMap.put(position.flipAroundMiddleRow(), pieceType.toPiece(TEAM_TYPE))); return positionPieceMap; } + + @Override + public String getName() { + return TEAM_TYPE.getName(); + } } diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java index 7384eaad43..98490f04e1 100644 --- a/src/main/java/janggi/domain/team/RedTeam.java +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -22,8 +22,15 @@ public Map generatePieces() { final Map positionPieceMap = new LinkedHashMap<>(); final Map positionPieceTypeMap = setupPolicy.offerBoardMap(); positionPieceTypeMap.forEach((position, pieceType) -> - positionPieceMap.put(position, pieceType.toPiece(TEAM_TYPE))); + positionPieceMap.put(position, pieceType.toPiece(TEAM_TYPE))); return positionPieceMap; } + + @Override + public String getName() { + return TEAM_TYPE.getName(); + } + + } diff --git a/src/main/java/janggi/domain/team/Team.java b/src/main/java/janggi/domain/team/Team.java index 53c942c029..d8bda186ed 100644 --- a/src/main/java/janggi/domain/team/Team.java +++ b/src/main/java/janggi/domain/team/Team.java @@ -6,4 +6,6 @@ public interface Team { Map generatePieces(); + + String getName(); } diff --git a/src/main/java/janggi/domain/team/TeamType.java b/src/main/java/janggi/domain/team/TeamType.java index f8b601200f..9de33406ce 100644 --- a/src/main/java/janggi/domain/team/TeamType.java +++ b/src/main/java/janggi/domain/team/TeamType.java @@ -1,5 +1,16 @@ package janggi.domain.team; public enum TeamType { - RED, BLUE; + RED("한나라"), + BLUE("초나라"); + + private final String name; + + TeamType(final String name) { + this.name = name; + } + + public String getName() { + return name; + } } diff --git a/src/main/java/janggi/utils/Parser.java b/src/main/java/janggi/utils/Parser.java new file mode 100644 index 0000000000..8c58d29c5b --- /dev/null +++ b/src/main/java/janggi/utils/Parser.java @@ -0,0 +1,15 @@ +package janggi.utils; + +public final class Parser { + + private Parser() { + } + + public static int parseInteger(final String input) { + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("정수만 입력할 수 있습니다."); + } + } +} diff --git a/src/main/java/janggi/utils/RetryExecutor.java b/src/main/java/janggi/utils/RetryExecutor.java new file mode 100644 index 0000000000..c819a4e66c --- /dev/null +++ b/src/main/java/janggi/utils/RetryExecutor.java @@ -0,0 +1,18 @@ +package janggi.utils; + +import janggi.view.OutputView; +import java.util.function.Supplier; + +public final class RetryExecutor { + private RetryExecutor() { + } + + public static T retry(final Supplier supplier) { + try { + return supplier.get(); + } catch (IllegalArgumentException e) { + OutputView.printErrorMessage(e.getMessage()); + return retry(supplier); + } + } +} diff --git a/src/main/java/janggi/view/InputView.java b/src/main/java/janggi/view/InputView.java new file mode 100644 index 0000000000..e54aa007ec --- /dev/null +++ b/src/main/java/janggi/view/InputView.java @@ -0,0 +1,13 @@ +package janggi.view; + +import janggi.utils.Parser; +import janggi.view.reader.Console; + +public final class InputView { + private InputView() { + } + + public static int readSetupCommand() { + return Parser.parseInteger(Console.readLine()); + } +} diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java new file mode 100644 index 0000000000..37bfbfeea1 --- /dev/null +++ b/src/main/java/janggi/view/OutputView.java @@ -0,0 +1,22 @@ +package janggi.view; + +import janggi.domain.command.SetupCommand; +import janggi.domain.team.TeamType; + +public final class OutputView { + private static final String ERROR_PREFIX = "[ERROR]: "; + + private OutputView() { + } + + public static void printSetupGuide(TeamType teamType) { + System.out.println(teamType.getName() + "의 차림법을 입력해주세요."); + for (final SetupCommand setupCommand : SetupCommand.values()) { + System.out.println(setupCommand.getNumber() + ". " + setupCommand.getDescription()); + } + } + + public static void printErrorMessage(String message) { + System.out.println(ERROR_PREFIX + message); + } +} diff --git a/src/main/java/janggi/view/reader/Console.java b/src/main/java/janggi/view/reader/Console.java new file mode 100644 index 0000000000..1e6ec5ce39 --- /dev/null +++ b/src/main/java/janggi/view/reader/Console.java @@ -0,0 +1,17 @@ +package janggi.view.reader; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Console { + private static final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in)); + + public static String readLine() { + try { + return READER.readLine(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} From bccd55597d584c4996f480637ff6849d197514e8 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 15:57:11 +0900 Subject: [PATCH 009/128] =?UTF-8?q?feat(output):=20=EB=B3=B4=EB=93=9C?= =?UTF-8?q?=ED=8C=90=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/Application.java | 11 +++ .../janggi/controller/JanggiController.java | 2 + src/main/java/janggi/domain/Position.java | 8 +- src/main/java/janggi/domain/board/Board.java | 4 +- src/main/java/janggi/domain/piece/Cannon.java | 10 +++ .../java/janggi/domain/piece/Chariot.java | 10 +++ .../java/janggi/domain/piece/Elephant.java | 10 +++ .../java/janggi/domain/piece/General.java | 10 +++ src/main/java/janggi/domain/piece/Guard.java | 12 ++- src/main/java/janggi/domain/piece/Horse.java | 10 +++ src/main/java/janggi/domain/piece/Piece.java | 6 +- .../java/janggi/domain/piece/Soldier.java | 14 +++- src/main/java/janggi/dto/BoardDto.java | 83 +++++++++++++++++++ src/main/java/janggi/global/Pair.java | 6 ++ src/main/java/janggi/utils/Lists.java | 25 ++++++ src/main/java/janggi/view/ConsoleColor.java | 20 +++++ src/main/java/janggi/view/OutputView.java | 14 ++++ 17 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 src/main/java/janggi/Application.java create mode 100644 src/main/java/janggi/dto/BoardDto.java create mode 100644 src/main/java/janggi/global/Pair.java create mode 100644 src/main/java/janggi/utils/Lists.java create mode 100644 src/main/java/janggi/view/ConsoleColor.java diff --git a/src/main/java/janggi/Application.java b/src/main/java/janggi/Application.java new file mode 100644 index 0000000000..18b64c6564 --- /dev/null +++ b/src/main/java/janggi/Application.java @@ -0,0 +1,11 @@ +package janggi; + +import janggi.controller.JanggiController; + +public class Application { + + public static void main(String[] args) { + final JanggiController janggiController = new JanggiController(); + janggiController.run(); + } +} diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 761268dbdf..943a15c034 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -8,6 +8,7 @@ import janggi.domain.team.RedTeam; import janggi.domain.team.Team; import janggi.domain.team.TeamType; +import janggi.dto.BoardDto; import janggi.utils.RetryExecutor; import janggi.view.InputView; import janggi.view.OutputView; @@ -34,6 +35,7 @@ public void run() { Team redTeam = setupRedTeam(); Team blueTeam = setupBlueTeam(); Board board = BoardGenerator.generate(redTeam, blueTeam); + OutputView.printBoard(BoardDto.from(board)); } private SetupCommand readSetupCommand() { diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 6bc95a4317..bc2aca57fa 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -5,10 +5,10 @@ public final class Position { - private static final int MAXIMUM_ROW = 10; - private static final int MAXIMUM_COLUMN = 9; - private static final int MINIMUM_ROW = 1; - private static final int MINIMUM_COLUMN = 1; + public static final int MAXIMUM_ROW = 10; + public static final int MAXIMUM_COLUMN = 9; + public static final int MINIMUM_ROW = 1; + public static final int MINIMUM_COLUMN = 1; private static final int ROW_FLIP_VALUE = 11; private static final Map> CACHE; diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index b051f2bd69..ffc0602ca3 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -12,5 +12,7 @@ public Board(final Map positionPieceMap) { this.positionPieceMap = positionPieceMap; } - + public Map getPositionPieceMap() { + return positionPieceMap; + } } diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index baa27ab851..22a2f5bab6 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -12,4 +12,14 @@ public class Cannon implements Piece { public Cannon(final TeamType teamType) { this.teamType = teamType; } + + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 113e341b97..0a311fc7ef 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -13,4 +13,14 @@ public Chariot(final TeamType teamType) { this.teamType = teamType; } + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } + } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 3e4ba71bf7..664658ec4a 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -12,4 +12,14 @@ public class Elephant implements Piece { public Elephant(final TeamType teamType) { this.teamType = teamType; } + + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index c89217a373..fe73865102 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -12,4 +12,14 @@ public class General implements Piece { public General(final TeamType teamType) { this.teamType = teamType; } + + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 14975a3a38..6325d0b52b 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -3,7 +3,7 @@ import janggi.domain.PieceType; import janggi.domain.team.TeamType; -public class Guard implements Piece{ +public class Guard implements Piece { private static final PieceType PIECE_TYPE = PieceType.GUARD; @@ -12,4 +12,14 @@ public class Guard implements Piece{ public Guard(final TeamType teamType) { this.teamType = teamType; } + + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 2adbdd8010..51d72e9220 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -12,4 +12,14 @@ public class Horse implements Piece { public Horse(final TeamType teamType) { this.teamType = teamType; } + + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 1940c72c84..e7a0ba35e3 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -1,5 +1,9 @@ package janggi.domain.piece; -public interface Piece { +import janggi.domain.PieceType; +import janggi.domain.team.TeamType; +public interface Piece { + PieceType getPieceType(); + TeamType getTeamType(); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 57c7f37a38..0051efb285 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -1,13 +1,25 @@ package janggi.domain.piece; +import janggi.domain.PieceType; import janggi.domain.team.TeamType; -public class Soldier implements Piece{ +public class Soldier implements Piece { + private static final PieceType PIECE_TYPE = PieceType.SOLDIER; private final TeamType teamType; public Soldier(final TeamType teamType) { this.teamType = teamType; } + @Override + public PieceType getPieceType() { + return PIECE_TYPE; + } + + @Override + public TeamType getTeamType() { + return teamType; + } + } diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java new file mode 100644 index 0000000000..14917adaa9 --- /dev/null +++ b/src/main/java/janggi/dto/BoardDto.java @@ -0,0 +1,83 @@ +package janggi.dto; + +import static janggi.domain.Position.MAXIMUM_COLUMN; +import static janggi.domain.Position.MAXIMUM_ROW; +import static janggi.domain.Position.MINIMUM_COLUMN; +import static janggi.domain.Position.MINIMUM_ROW; + +import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.Board; +import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; +import janggi.view.ConsoleColor; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public record BoardDto( + List rowStatuses +) { + + private static final Map> CHINESE_MAP; + private static final String EMPTY_SPACE = "*"; + private static final String DELIMITER = " "; + + static { + CHINESE_MAP = Map.of( + TeamType.RED, Map.of( + PieceType.GENERAL, ConsoleColor.red("漢"), + PieceType.GUARD, ConsoleColor.red("士"), + PieceType.CHARIOT, ConsoleColor.red("車"), + PieceType.CANNON, ConsoleColor.red("包"), + PieceType.HORSE, ConsoleColor.red("馬"), + PieceType.ELEPHANT, ConsoleColor.red("象"), + PieceType.SOLDIER, ConsoleColor.red("兵") + ), + TeamType.BLUE, Map.of( + PieceType.GENERAL, ConsoleColor.blue("楚"), + PieceType.GUARD, ConsoleColor.blue("士"), + PieceType.CHARIOT, ConsoleColor.blue("車"), + PieceType.CANNON, ConsoleColor.blue("包"), + PieceType.HORSE, ConsoleColor.blue("馬"), + PieceType.ELEPHANT, ConsoleColor.blue("象"), + PieceType.SOLDIER, ConsoleColor.blue("卒") + )); + } + + public static BoardDto from(final Board board) { + final List rowStatuses = new ArrayList<>(); + final Map positionPieceMap = board.getPositionPieceMap(); + for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { + rowStatuses.add(composeRowStatus(row, positionPieceMap)); + } + + return new BoardDto(rowStatuses); + } + + private static String composeRowStatus(final int row, final Map positionPieceMap) { + final StringBuilder stringBuilder = new StringBuilder(); + Position current; + for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { + current = Position.valueOf(row, column); + stringBuilder.append(DELIMITER); + stringBuilder.append(getSpace(current, positionPieceMap)); + } + + return stringBuilder.toString(); + } + + private static String getSpace(final Position position, final Map positionPieceMap) { + if (positionPieceMap.containsKey(position)) { + final Piece piece = positionPieceMap.get(position); + return getChineseOf(piece); + } + return EMPTY_SPACE; + } + + private static String getChineseOf(final Piece piece) { + final Map secondaryMap = CHINESE_MAP.get(piece.getTeamType()); + return secondaryMap.get(piece.getPieceType()); + } + +} diff --git a/src/main/java/janggi/global/Pair.java b/src/main/java/janggi/global/Pair.java new file mode 100644 index 0000000000..715f406b68 --- /dev/null +++ b/src/main/java/janggi/global/Pair.java @@ -0,0 +1,6 @@ +package janggi.global; + +public record Pair(T left, U right) { + +} + diff --git a/src/main/java/janggi/utils/Lists.java b/src/main/java/janggi/utils/Lists.java new file mode 100644 index 0000000000..91fd907b42 --- /dev/null +++ b/src/main/java/janggi/utils/Lists.java @@ -0,0 +1,25 @@ +package janggi.utils; + +import janggi.global.Pair; +import java.util.List; +import java.util.stream.Stream; + +public final class Lists { + + private Lists() { + + } + + public static List> cartesianProduct(final List list1, + final List list2) { + return list1.stream() + .flatMap(t -> pairWithAll(t, list2)) + .toList(); + } + + private static Stream> pairWithAll(final T t, final List list) { + return list.stream() + .map(u -> new Pair<>(t, u)); + } + +} diff --git a/src/main/java/janggi/view/ConsoleColor.java b/src/main/java/janggi/view/ConsoleColor.java new file mode 100644 index 0000000000..1d989e314d --- /dev/null +++ b/src/main/java/janggi/view/ConsoleColor.java @@ -0,0 +1,20 @@ +package janggi.view; + +public final class ConsoleColor { + + private static final String RED = "\u001B[31m"; + private static final String BLUE = "\u001B[34m"; + private static final String EXIT = "\u001B[0m"; + + private ConsoleColor() { + } + + public static String red(final String string) { + return RED + string + EXIT; + } + + public static String blue(final String string) { + return BLUE + string + EXIT; + } + +} diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index 37bfbfeea1..d1f0e27910 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -1,7 +1,13 @@ package janggi.view; +import janggi.domain.Position; +import janggi.domain.board.Board; import janggi.domain.command.SetupCommand; +import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; +import janggi.dto.BoardDto; +import java.util.List; +import java.util.Map; public final class OutputView { private static final String ERROR_PREFIX = "[ERROR]: "; @@ -19,4 +25,12 @@ public static void printSetupGuide(TeamType teamType) { public static void printErrorMessage(String message) { System.out.println(ERROR_PREFIX + message); } + + public static void printBoard(final BoardDto boardDto) { + final List rowStatuses = boardDto.rowStatuses(); + + for (String rowStatus : rowStatuses) { + System.out.println(rowStatus); + } + } } From 1faa91fb1de8cf824ebc6a8783d9712df7f46aaa Mon Sep 17 00:00:00 2001 From: mvg01 Date: Wed, 25 Mar 2026 17:19:29 +0900 Subject: [PATCH 010/128] =?UTF-8?q?docs(readme):=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EA=B5=AC=ED=98=84=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=AA=A9=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 | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5fbcb1d22a..41f0c24f1f 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,38 @@ # 구현 기능 - 보드 초기화 - - 각 플레이어에게 장기판 차림 방법을 입력 받는다. - - 먼저 플레이하는 초나라부터 명령 번호를 입력하여 판차림 방법을 결정한다. - - 1, 2, 3, 4 이외의 숫자가 들어오는 경우 예외 처리한다. - - 선택할 수 있는 판차림은 다음과 같다. - 1. 왼상 차림 - 2. 오른상 차림 - 3. 안상 차림 - 4. 바깥상 차림 - - 입력한 장기판 차림을 기반으로 보드를 세팅한다. - - 보드 출력 - - 빈 공간은 온점 전각 문자를 활용한다. - - 팀 구분은 색상(빨강, 파랑)으로 구분한다. - - 기물은 각 기물에 대응하는 한나라의 한자로 표기한다. \ No newline at end of file + - 각 플레이어에게 장기판 차림 방법을 입력 받는다. + - 먼저 플레이하는 초나라부터 명령 번호를 입력하여 판차림 방법을 결정한다. + - 1, 2, 3, 4 이외의 숫자가 들어오는 경우 예외 처리한다. + - 선택할 수 있는 판차림은 다음과 같다. + 1. 왼상 차림 + 2. 오른상 차림 + 3. 안상 차림 + 4. 바깥상 차림 + - 입력한 장기판 차림을 기반으로 보드를 세팅한다. + - 보드 출력 + - 빈 공간은 온점 전각 문자를 활용한다. + - 팀 구분은 색상(빨강, 파랑)으로 구분한다. + - 기물은 각 기물에 대응하는 한나라의 한자로 표기한다. + +- 기물 이동 구현 + - 움직일 기물의 좌표를 플레이어에게 입력받는다. + - 다음의 경우 다시 입력받는다. + - `row`, `column` 형식이 아닌 경우 + - 플레이어의 팀이 아닌 기물의 좌표를 입력한 경우 + - 입력한 기물이 이동 가능한 위치가 없는 경우 + - 입력받은 위치의 기물이 이동 가능한 위치를 출력한다. + - 이동 가능한 위치는 초록색으로 표현된다. + - 플레이어에게 이동 가능한 위치 중 하나를 입력받는다. + - 다음의 경우 다시 입력받는다. + - `row`, `column` 형식이 아닌 경우 + - 이동 가능한 위치가 아닌 경우 + - 입력받은 위치로 기물을 이동시킨다. + - 각 기물의 이동 규칙은 다음과 같다. + - 차 (車): 가로/세로 직선 이동가능, 거리 제한 없음, 중간에 기물이 있으면 못 지나감 + - 마 (馬): 1칸 직선 + 1칸 대각선, 가는 길이 막히면 이동 불가 + - 상 (象): 1칸 직선 + 2칸 대각선, 가는 길이 막히면 이동 불가 + - 사 (士): 모든 방향으로 1칸 이동 가능 + - 장 (將): 모든 방향으로 1칸 이동 가능 + - 포 (砲): 반드시 하나를 넘어 전후좌우로 이동이 가능하고 포는 서로 넘거나 잡을 수 없다. + - 졸 (卒): 앞, 왼쪽, 오른쪽 1칸씩 이동 가능 \ No newline at end of file From 455379e4f42c20189bf8e92866ffc3ec44b36f40 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Wed, 25 Mar 2026 17:33:05 +0900 Subject: [PATCH 011/128] =?UTF-8?q?test(parser):=20=EC=A0=95=EC=88=98=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=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 --- src/test/java/janggi/utils/ParserTest.java | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/java/janggi/utils/ParserTest.java diff --git a/src/test/java/janggi/utils/ParserTest.java b/src/test/java/janggi/utils/ParserTest.java new file mode 100644 index 0000000000..be2460429e --- /dev/null +++ b/src/test/java/janggi/utils/ParserTest.java @@ -0,0 +1,38 @@ +package janggi.utils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class ParserTest { + + @Nested + @DisplayName("정수 파싱 테스트") + class ParseInteger { + + @Test + @DisplayName("정상 테스트") + void success1() { + // given + String input = "10"; + int expected = Integer.valueOf(input); + + // when + int actual = Parser.parseInteger(input); + + // then + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("정수가 아닌 값을 변환하는 경우 테스트") + void failure1() { + String input = "test"; + assertThatIllegalArgumentException() + .isThrownBy(() -> Parser.parseInteger(input)); + } + } +} From 7f4caa6c422415a52152b48271d5211f91851d30 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 18:02:29 +0900 Subject: [PATCH 012/128] =?UTF-8?q?test(board):=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=8C=80=20=EA=B8=B0=EB=AC=BC=20=EC=97=AC=EB=B6=80=20=ED=85=8C?= =?UTF-8?q?=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/janggi/domain/BoardTest.java | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/test/java/janggi/domain/BoardTest.java diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java new file mode 100644 index 0000000000..a1f8fa7e58 --- /dev/null +++ b/src/test/java/janggi/domain/BoardTest.java @@ -0,0 +1,55 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.piece.Cannon; +import janggi.domain.piece.Piece; +import janggi.domain.team.BlueTeam; +import janggi.domain.team.RedTeam; +import janggi.domain.team.Team; +import janggi.domain.team.TeamType; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class BoardTest { + + @Nested + @DisplayName("특정 팀 기물 여부 테스트") + class CheckPieceOfTeam { + + @Test + @DisplayName("특정 팀의 기물인 경우") + void success_1() { + Team redTeam = new RedTeam(new InnerElephantSetupPolicy()); + Position position = Position.valueOf(1, 1); + Map positionPieceMap = Map.of( + position, new Cannon(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + boolean expected = true; + + boolean actual = board.checkPieceOfTeam(redTeam, position); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("특정 팀의 기물이 아닌 경우") + void success_2() { + Team blueTeam = new BlueTeam(new InnerElephantSetupPolicy()); + Position position = Position.valueOf(1, 1); + Map positionPieceMap = Map.of( + position, new Cannon(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + boolean expected = false; + + boolean actual = board.checkPieceOfTeam(blueTeam, position); + + assertThat(actual).isEqualTo(expected); + } + } +} From 45894d775c244b54750a770f865a0a73c283179b Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 18:42:12 +0900 Subject: [PATCH 013/128] =?UTF-8?q?test(board):=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=8C=80=20=EA=B8=B0=EB=AC=BC=20=EC=97=AC=EB=B6=80=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=97=90=20=EB=B9=88=20=EC=B9=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=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/janggi/domain/BoardTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index a1f8fa7e58..ec156adea6 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -51,5 +51,19 @@ position, new Cannon(TeamType.RED) assertThat(actual).isEqualTo(expected); } + + @Test + @DisplayName("빈 칸인 경우") + void success_3() { + Team blueTeam = new BlueTeam(new InnerElephantSetupPolicy()); + Position position = Position.valueOf(1, 5); + Map positionPieceMap = Map.of(); + Board board = new Board(positionPieceMap); + boolean expected = false; + + boolean actual = board.checkPieceOfTeam(blueTeam, position); + + assertThat(actual).isEqualTo(expected); + } } } From ea4a672abe18574613016a2e79c2411ededa4a69 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 18:51:03 +0900 Subject: [PATCH 014/128] =?UTF-8?q?test(board):=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=8C=80=20=EA=B8=B0=EB=AC=BC=20=EC=97=AC=EB=B6=80=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/BoardTest.java | 64 ---------------------- 1 file changed, 64 deletions(-) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index ec156adea6..4146788c58 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,69 +1,5 @@ package janggi.domain; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import janggi.domain.board.Board; -import janggi.domain.piece.Cannon; -import janggi.domain.piece.Piece; -import janggi.domain.team.BlueTeam; -import janggi.domain.team.RedTeam; -import janggi.domain.team.Team; -import janggi.domain.team.TeamType; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - public class BoardTest { - @Nested - @DisplayName("특정 팀 기물 여부 테스트") - class CheckPieceOfTeam { - - @Test - @DisplayName("특정 팀의 기물인 경우") - void success_1() { - Team redTeam = new RedTeam(new InnerElephantSetupPolicy()); - Position position = Position.valueOf(1, 1); - Map positionPieceMap = Map.of( - position, new Cannon(TeamType.RED) - ); - Board board = new Board(positionPieceMap); - boolean expected = true; - - boolean actual = board.checkPieceOfTeam(redTeam, position); - - assertThat(actual).isEqualTo(expected); - } - - @Test - @DisplayName("특정 팀의 기물이 아닌 경우") - void success_2() { - Team blueTeam = new BlueTeam(new InnerElephantSetupPolicy()); - Position position = Position.valueOf(1, 1); - Map positionPieceMap = Map.of( - position, new Cannon(TeamType.RED) - ); - Board board = new Board(positionPieceMap); - boolean expected = false; - - boolean actual = board.checkPieceOfTeam(blueTeam, position); - - assertThat(actual).isEqualTo(expected); - } - - @Test - @DisplayName("빈 칸인 경우") - void success_3() { - Team blueTeam = new BlueTeam(new InnerElephantSetupPolicy()); - Position position = Position.valueOf(1, 5); - Map positionPieceMap = Map.of(); - Board board = new Board(positionPieceMap); - boolean expected = false; - - boolean actual = board.checkPieceOfTeam(blueTeam, position); - - assertThat(actual).isEqualTo(expected); - } - } } From 4062415dae607a91b13bc0cbbab216225a66f2ab Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 18:54:37 +0900 Subject: [PATCH 015/128] =?UTF-8?q?test(board):=20=EB=B9=88=EC=B9=B8=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=8C=90=EC=A0=95=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 --- src/test/java/janggi/domain/BoardTest.java | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 4146788c58..da9b1b93b3 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,5 +1,47 @@ package janggi.domain; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.piece.Cannon; +import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + public class BoardTest { + @Nested + @DisplayName("빈칸 여부 테스트") + class isBlank { + + @Test + @DisplayName("빈칸인 경우") + void success_1() { + Board board = new Board(new LinkedHashMap<>()); + Position position = Position.valueOf(1, 1); + boolean expected = true; + + boolean actual = board.isBlank(position); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("빈칸이 아닌 경우") + void success_2() { + Position position = Position.valueOf(1, 1); + Map positionPieceMap = Map.of( + position, new Cannon(TeamType.RED)); + Board board = new Board(positionPieceMap); + boolean expected = false; + + boolean actual = board.isBlank(position); + + assertThat(actual).isEqualTo(expected); + } + } } From fc807dae44bd064b88a11ddea4ed28c2c1f9c6d1 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 18:56:05 +0900 Subject: [PATCH 016/128] =?UTF-8?q?feat(board):=20=EB=B9=88=EC=B9=B8=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=8C=90=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Board.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index ffc0602ca3..a6bab90c8a 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -2,6 +2,7 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; +import janggi.domain.team.Team; import java.util.Map; public class Board { @@ -15,4 +16,8 @@ public Board(final Map positionPieceMap) { public Map getPositionPieceMap() { return positionPieceMap; } + + public boolean isBlank(final Position position) { + return !positionPieceMap.containsKey(position); + } } From 5168752eeb35ba373414074b629dece6c58ea7a9 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 19:07:44 +0900 Subject: [PATCH 017/128] =?UTF-8?q?test(board):=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=ED=9A=8D=EB=93=9D=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 --- src/test/java/janggi/domain/BoardTest.java | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index da9b1b93b3..c41960378e 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,5 +1,6 @@ package janggi.domain; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.board.Board; @@ -44,4 +45,34 @@ void success_2() { assertThat(actual).isEqualTo(expected); } } + + @Nested + @DisplayName("기물 획득 테스트") + class FindPieceByPosition { + + @Test + @DisplayName("정상 테스트") + void success() { + Position position = Position.valueOf(1, 1); + Piece expected = new Cannon(TeamType.RED); + Map positionPieceMap = Map.of( + position, expected); + Board board = new Board(positionPieceMap); + + Board actual = board.findPieceByPosition(position); + + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } + + @Test + @DisplayName("빈칸인 경우 예외가 발생한다.") + void failure() { + Position position = Position.valueOf(1, 1); + Board board = new Board(new LinkedHashMap<>()); + + assertThatIllegalArgumentException() + .isThrownBy(() -> board.findPieceByPosition(position)); + } + } } From 95df400217e3a7c68eaadf9ade4b3a3a26e6257a Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 19:08:41 +0900 Subject: [PATCH 018/128] =?UTF-8?q?feat(board):=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=ED=9A=8D=EB=93=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Board.java | 7 +++++++ src/test/java/janggi/domain/BoardTest.java | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index a6bab90c8a..68cbd30ab8 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -20,4 +20,11 @@ public Map getPositionPieceMap() { public boolean isBlank(final Position position) { return !positionPieceMap.containsKey(position); } + + public Piece findPieceByPosition(final Position position) { + if (isBlank(position)) { + throw new IllegalStateException("요청된 위치에는 기물이 존재하지 않습니다."); + } + return positionPieceMap.get(position); + } } diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index c41960378e..d7aa6cb201 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,6 +1,7 @@ package janggi.domain; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.board.Board; @@ -59,7 +60,7 @@ void success() { position, expected); Board board = new Board(positionPieceMap); - Board actual = board.findPieceByPosition(position); + Piece actual = board.findPieceByPosition(position); assertThat(actual).usingRecursiveComparison() .isEqualTo(expected); @@ -71,7 +72,7 @@ void failure() { Position position = Position.valueOf(1, 1); Board board = new Board(new LinkedHashMap<>()); - assertThatIllegalArgumentException() + assertThatIllegalStateException() .isThrownBy(() -> board.findPieceByPosition(position)); } } From 09263e1c887428888aefbbec6d976ffc3886db9d Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 19:23:30 +0900 Subject: [PATCH 019/128] =?UTF-8?q?test(piece):=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=8C=80=20=EA=B8=B0=EB=AC=BC=20=EC=97=AC=EB=B6=80=20=ED=8C=90?= =?UTF-8?q?=EC=A0=95=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/janggi/domain/PieceTest.java | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/test/java/janggi/domain/PieceTest.java diff --git a/src/test/java/janggi/domain/PieceTest.java b/src/test/java/janggi/domain/PieceTest.java new file mode 100644 index 0000000000..8fcaf711a4 --- /dev/null +++ b/src/test/java/janggi/domain/PieceTest.java @@ -0,0 +1,44 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import janggi.domain.piece.Cannon; +import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class PieceTest { + + + @Nested + @DisplayName("특정 팀 기물 여부 판정 테스트") + class belongsToTeam { + + @Test + @DisplayName("특정 팀에 해당하는 경우") + void success_1() { + TeamType teamType = TeamType.RED; + Piece cannon = new Cannon(teamType); + boolean expected = true; + + boolean actual = cannon.belongsToTeam(teamType); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("특정 팀에 해당하지 않는 경우") + void success_2() { + TeamType teamType = TeamType.RED; + TeamType otherTeamType = TeamType.BLUE; + Piece cannon = new Cannon(otherTeamType); + boolean expected = false; + + boolean actual = cannon.belongsToTeam(teamType); + + assertThat(actual).isEqualTo(expected); + } + } +} From 43276c9201fb6a116248f86da5d6444b0a7b5ec6 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Wed, 25 Mar 2026 19:23:38 +0900 Subject: [PATCH 020/128] =?UTF-8?q?feat(piece):=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=8C=80=20=EA=B8=B0=EB=AC=BC=20=EC=97=AC=EB=B6=80=20=ED=8C=90?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cannon.java | 5 +++++ src/main/java/janggi/domain/piece/Chariot.java | 5 +++++ src/main/java/janggi/domain/piece/Elephant.java | 5 +++++ src/main/java/janggi/domain/piece/General.java | 5 +++++ src/main/java/janggi/domain/piece/Guard.java | 5 +++++ src/main/java/janggi/domain/piece/Horse.java | 5 +++++ src/main/java/janggi/domain/piece/Piece.java | 1 + src/main/java/janggi/domain/piece/Soldier.java | 5 +++++ src/main/java/janggi/domain/team/BlueTeam.java | 5 +++++ src/main/java/janggi/domain/team/RedTeam.java | 5 +++++ src/main/java/janggi/domain/team/Team.java | 2 ++ 11 files changed, 48 insertions(+) diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 22a2f5bab6..1ba80aff0d 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -22,4 +22,9 @@ public PieceType getPieceType() { public TeamType getTeamType() { return teamType; } + + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 0a311fc7ef..57bc8927ee 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -23,4 +23,9 @@ public TeamType getTeamType() { return teamType; } + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } + } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 664658ec4a..ea29fc9895 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -22,4 +22,9 @@ public PieceType getPieceType() { public TeamType getTeamType() { return teamType; } + + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index fe73865102..5e000882d0 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -22,4 +22,9 @@ public PieceType getPieceType() { public TeamType getTeamType() { return teamType; } + + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 6325d0b52b..262d910796 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -22,4 +22,9 @@ public PieceType getPieceType() { public TeamType getTeamType() { return teamType; } + + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 51d72e9220..c7a369df7e 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -22,4 +22,9 @@ public PieceType getPieceType() { public TeamType getTeamType() { return teamType; } + + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index e7a0ba35e3..b42e9a644d 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -6,4 +6,5 @@ public interface Piece { PieceType getPieceType(); TeamType getTeamType(); + boolean belongsToTeam(TeamType teamType); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 0051efb285..cdf3ecf97d 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -22,4 +22,9 @@ public TeamType getTeamType() { return teamType; } + @Override + public boolean belongsToTeam(final TeamType teamType) { + return this.teamType == teamType; + } + } diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java index 81920d5b45..87735ec45f 100644 --- a/src/main/java/janggi/domain/team/BlueTeam.java +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -30,4 +30,9 @@ public Map generatePieces() { public String getName() { return TEAM_TYPE.getName(); } + + @Override + public boolean hasPiece(final Piece piece) { + return piece.belongsToTeam(TEAM_TYPE); + } } diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java index 98490f04e1..537b0dcb6f 100644 --- a/src/main/java/janggi/domain/team/RedTeam.java +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -32,5 +32,10 @@ public String getName() { return TEAM_TYPE.getName(); } + @Override + public boolean hasPiece(final Piece piece) { + return piece.belongsToTeam(TEAM_TYPE); + } + } diff --git a/src/main/java/janggi/domain/team/Team.java b/src/main/java/janggi/domain/team/Team.java index d8bda186ed..f44a0c3da1 100644 --- a/src/main/java/janggi/domain/team/Team.java +++ b/src/main/java/janggi/domain/team/Team.java @@ -8,4 +8,6 @@ public interface Team { Map generatePieces(); String getName(); + + boolean hasPiece(Piece piece); } From 313d5e52831f2e5863f6c2b2bf1af8c12c4ddbfc Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 13:03:15 +0900 Subject: [PATCH 021/128] =?UTF-8?q?feat(board):=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=ED=95=9C=20=EA=B8=B0=EB=AC=BC=20=EC=9C=84=EC=B9=98=EB=A7=B5=20?= =?UTF-8?q?=EC=A0=9C=EA=B3=B5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Board.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 68cbd30ab8..1571a377dc 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -2,7 +2,8 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; -import janggi.domain.team.Team; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; public class Board { @@ -27,4 +28,15 @@ public Piece findPieceByPosition(final Position position) { } return positionPieceMap.get(position); } + + public Map offerSelectedPieceMap(final List positions) { + final Map selected = new LinkedHashMap<>(); + positions.forEach(position -> { + if (!isBlank(position)) { + selected.put(position, findPieceByPosition(position)); + } + }); + + return selected; + } } From 2daa9474a8a5a4f6e880dbc65fb210f5a89e2854 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 26 Mar 2026 13:23:25 +0900 Subject: [PATCH 022/128] =?UTF-8?q?test(chariot):=20=EC=B0=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=9C=20=EC=9C=84=EC=B9=98=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/ChariotTest.java | 104 +++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/test/java/janggi/domain/ChariotTest.java diff --git a/src/test/java/janggi/domain/ChariotTest.java b/src/test/java/janggi/domain/ChariotTest.java new file mode 100644 index 0000000000..d2a9dd4a2c --- /dev/null +++ b/src/test/java/janggi/domain/ChariotTest.java @@ -0,0 +1,104 @@ +package janggi.domain; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.piece.Chariot; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class ChariotTest { + + @Nested + @DisplayName("이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece chariot; + static Piece enemy1; + static Piece enemy2; + static Piece enemy3; + static Piece enemy4; + static Piece ally1; + static Piece ally2; + static Piece ally3; + static Piece ally4; + static Map positionPieceMap; + static List candidatePositions; + + @BeforeEach + void setUp() { + chariot = new Chariot(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy3 = new Soldier(TeamType.BLUE); + enemy4 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + ally3 = new Soldier(TeamType.RED); + ally4 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap(); + candidatePositions = initCanididatePositions(); + } + + @Test + @DisplayName("차는 적군을 뛰어넘어 갈 수 없다.") + void test1() { + positionPieceMap.put(Position.valueOf(5, 3), chariot); + positionPieceMap.put(Position.valueOf(5, 1), ally1); + positionPieceMap.put(Position.valueOf(3, 3), ally2); + positionPieceMap.put(Position.valueOf(5, 6), ally3); + positionPieceMap.put(Position.valueOf(7, 3), ally4); + List expected = List.of(Position.valueOf(3, 3), Position.valueOf(4, 3), Position.valueOf(5, 1), + Position.valueOf(5, 2), Position.valueOf(5, 4), + Position.valueOf(5, 5), Position.valueOf(5, 6), + Position.valueOf(6, 3), Position.valueOf(7, 3)); + + Board board = new Board(positionPieceMap); + Map offeredSelectedPieceMap = board.offerSelectedPieceMap(candidatePositions); + List actual = chariot.calculateMovablePositions(offeredSelectedPieceMap, Position.valueOf(5, 3)); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("차는 아군을 뛰어넘어 갈 수 없다.") + void test2() { + positionPieceMap.put(Position.valueOf(5, 3), chariot); + positionPieceMap.put(Position.valueOf(5, 1), ally1); + positionPieceMap.put(Position.valueOf(3, 3), ally2); + positionPieceMap.put(Position.valueOf(5, 6), ally3); + positionPieceMap.put(Position.valueOf(7, 3), ally4); + List expected = List.of(Position.valueOf(4, 3), + Position.valueOf(5, 2), Position.valueOf(5, 4), + Position.valueOf(5, 5), Position.valueOf(6, 3)); + + Board board = new Board(positionPieceMap); + Map offeredSelectedPieceMap = board.offerSelectedPieceMap(candidatePositions); + List actual = chariot.calculateMovablePositions(offeredSelectedPieceMap, Position.valueOf(5, 3)); + + assertThat(actual).hasSameElementsAs(expected); + } + + List initCanididatePositions() { + List candidatePositions = new ArrayList<>(); + for (int row = 1; row <= 10; row++) { + candidatePositions.add(Position.valueOf(row, 3)); + } + for (int column = 1; column <= 9; column++) { + candidatePositions.add(Position.valueOf(5, column)); + } + candidatePositions.remove(Position.valueOf(5, 3)); + candidatePositions.remove(Position.valueOf(5, 3)); + return candidatePositions; + } + } +} From c05930b68043af38257aaa4ebe674bd84618982d Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 13:38:16 +0900 Subject: [PATCH 023/128] =?UTF-8?q?test(position):=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1=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 --- src/test/java/janggi/domain/PositionTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/java/janggi/domain/PositionTest.java diff --git a/src/test/java/janggi/domain/PositionTest.java b/src/test/java/janggi/domain/PositionTest.java new file mode 100644 index 0000000000..e72a5dbc64 --- /dev/null +++ b/src/test/java/janggi/domain/PositionTest.java @@ -0,0 +1,45 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class PositionTest { + + @Nested + @DisplayName("생성 테스트") + class Constructor { + + @Test + @DisplayName("정상 테스트") + void success() { + int row = 1; + int column = 1; + + assertDoesNotThrow(() -> Position.valueOf(row, column)); + } + + @Test + @DisplayName("행 값이 범위를 벗어난 경우") + void failure_1() { + int wrongRow = 11; + int column = 1; + + assertThatIllegalArgumentException() + .isThrownBy(() -> Position.valueOf(wrongRow, column)); + } + + @Test + @DisplayName("열 값이 범위를 벗어난 경우") + void failure_2() { + int wrongRow = 1; + int column = 10; + + assertThatIllegalArgumentException() + .isThrownBy(() -> Position.valueOf(wrongRow, column)); + } + } +} \ No newline at end of file From e9b78ba6642d5fb7fad268248bbf960e1d89b70e Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 13:39:11 +0900 Subject: [PATCH 024/128] =?UTF-8?q?fix(position):=20=EC=9E=98=EB=AA=BB?= =?UTF-8?q?=EB=90=9C=20=EA=B0=92=20=EC=9E=85=EB=A0=A5=20=EC=8B=9C=20NPE?= =?UTF-8?q?=EA=B0=80=20=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Position.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index bc2aca57fa..4bf19670c9 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -23,13 +23,13 @@ public final class Position { private final int column; private Position(final int row, final int column) { - validateRowRange(row); - validateColumnRange(column); this.row = row; this.column = column; } public static Position valueOf(final int row, final int column) { + validateRowRange(row); + validateColumnRange(column); final Map secondaryMap = CACHE.get(row); if (!secondaryMap.containsKey(column)) { secondaryMap.put(column, new Position(row, column)); @@ -41,13 +41,13 @@ public Position flipAroundMiddleRow() { return Position.valueOf(ROW_FLIP_VALUE - row, column); } - private void validateRowRange(final int row) { + private static void validateRowRange(final int row) { if (row < MINIMUM_ROW || row > MAXIMUM_ROW) { throw new IllegalArgumentException("행 입력은 1~10을 입력해야 합니다."); } } - private void validateColumnRange(final int column) { + private static void validateColumnRange(final int column) { if (column < MINIMUM_COLUMN || column > MAXIMUM_COLUMN) { throw new IllegalArgumentException("열 입력은 1~9을 입력해야 합니다."); } From 60feacf6bb2f374d673af7f8633652cf32a135db Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 13:40:38 +0900 Subject: [PATCH 025/128] =?UTF-8?q?test(direction):=20=EB=B0=A9=ED=96=A5?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1=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 --- .../java/janggi/domain/DirectionTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/java/janggi/domain/DirectionTest.java diff --git a/src/test/java/janggi/domain/DirectionTest.java b/src/test/java/janggi/domain/DirectionTest.java new file mode 100644 index 0000000000..7d509286ce --- /dev/null +++ b/src/test/java/janggi/domain/DirectionTest.java @@ -0,0 +1,45 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class DirectionTest { + + @Nested + @DisplayName("생성 테스트") + class Constructor { + + @Test + @DisplayName("정상 테스트") + void success() { + int row = 1; + int column = 1; + + assertDoesNotThrow(() -> Position.valueOf(row, column)); + } + + @Test + @DisplayName("행 방향 값이 범위를 벗어난 경우") + void failure_1() { + int wrongRow = 2; + int column = 1; + + assertThatIllegalArgumentException() + .isThrownBy(() -> Position.valueOf(wrongRow, column)); + } + + @Test + @DisplayName("열 방향 값이 범위를 벗어난 경우") + void failure_2() { + int wrongRow = 1; + int column = 2; + + assertThatIllegalArgumentException() + .isThrownBy(() -> Position.valueOf(wrongRow, column)); + } + } +} \ No newline at end of file From 159f9a37f44a665bec1bf57292a018cfeb0ce6e0 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 13:45:58 +0900 Subject: [PATCH 026/128] =?UTF-8?q?feat(direction):=20=EB=B0=A9=ED=96=A5?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/movement/Direction.java | 56 +++++++++++++++++++ .../java/janggi/domain/DirectionTest.java | 7 ++- 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/main/java/janggi/domain/movement/Direction.java diff --git a/src/main/java/janggi/domain/movement/Direction.java b/src/main/java/janggi/domain/movement/Direction.java new file mode 100644 index 0000000000..934885513c --- /dev/null +++ b/src/main/java/janggi/domain/movement/Direction.java @@ -0,0 +1,56 @@ +package janggi.domain.movement; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.IntStream; + +public final class Direction { + + private static final int MINIMUM_ROW_DIRECTION = -1; + private static final int MAXIMUM_ROW_DIRECTION = 1; + private static final int MINIMUM_COLUMN_DIRECTION = -1; + private static final int MAXIMUM_COLUMN_DIRECTION = 1; + private static final Map> CACHE; + + static { + CACHE = new LinkedHashMap<>(); + IntStream.range(MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION + 1) + .forEach(rowDirection -> CACHE.put(rowDirection, new LinkedHashMap<>())); + } + + private final int rowDirection; + private final int columnDirection; + + private Direction(final int rowDirection, final int columnDirection) { + this.rowDirection = rowDirection; + this.columnDirection = columnDirection; + } + + public static Direction valueOf(final int rowDirection, final int columnDirection) { + validateRowDirectionRange(rowDirection); + validateColumnDirectionRange(columnDirection); + final Map secondaryMap = CACHE.get(rowDirection); + if (!secondaryMap.containsKey(columnDirection)) { + secondaryMap.put(columnDirection, new Direction(rowDirection, columnDirection)); + } + + return secondaryMap.get(columnDirection); + } + + private static void validateRowDirectionRange(final int rowDirection) { + if (rowDirection < MINIMUM_ROW_DIRECTION || rowDirection > MAXIMUM_ROW_DIRECTION) { + throw new IllegalArgumentException(String.format( + "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_ROW_DIRECTION, MAXIMUM_ROW_DIRECTION)); + } + } + + private static void validateColumnDirectionRange(final int columnDirection) { + if (columnDirection < MINIMUM_COLUMN_DIRECTION || columnDirection > MAXIMUM_COLUMN_DIRECTION) { + throw new IllegalArgumentException(String.format( + "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION)); + } + } + + + +} diff --git a/src/test/java/janggi/domain/DirectionTest.java b/src/test/java/janggi/domain/DirectionTest.java index 7d509286ce..723c1f96af 100644 --- a/src/test/java/janggi/domain/DirectionTest.java +++ b/src/test/java/janggi/domain/DirectionTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.jupiter.api.Assertions.*; +import janggi.domain.movement.Direction; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -19,7 +20,7 @@ void success() { int row = 1; int column = 1; - assertDoesNotThrow(() -> Position.valueOf(row, column)); + assertDoesNotThrow(() -> Direction.valueOf(row, column)); } @Test @@ -29,7 +30,7 @@ void failure_1() { int column = 1; assertThatIllegalArgumentException() - .isThrownBy(() -> Position.valueOf(wrongRow, column)); + .isThrownBy(() -> Direction.valueOf(wrongRow, column)); } @Test @@ -39,7 +40,7 @@ void failure_2() { int column = 2; assertThatIllegalArgumentException() - .isThrownBy(() -> Position.valueOf(wrongRow, column)); + .isThrownBy(() -> Direction.valueOf(wrongRow, column)); } } } \ No newline at end of file From 2bdd2aa4082072308c96642c4307ace220aa0eea Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 15:48:45 +0900 Subject: [PATCH 027/128] =?UTF-8?q?test(straight-movement):=20=EB=8F=84?= =?UTF-8?q?=EB=8B=AC=20=EC=97=AC=EB=B6=80=20=ED=8C=90=EC=A0=95=20=ED=85=8C?= =?UTF-8?q?=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 --- .../domain/movement/StraightMovementTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/test/java/janggi/domain/movement/StraightMovementTest.java diff --git a/src/test/java/janggi/domain/movement/StraightMovementTest.java b/src/test/java/janggi/domain/movement/StraightMovementTest.java new file mode 100644 index 0000000000..4c7ff05e76 --- /dev/null +++ b/src/test/java/janggi/domain/movement/StraightMovementTest.java @@ -0,0 +1,62 @@ +package janggi.domain.movement; + +import static janggi.domain.Position.MAXIMUM_ROW; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import janggi.domain.Position; +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class StraightMovementTest { + + @Nested + @DisplayName("도달 여부 판정 테스트") + class CanReach { + + Board board; + BoardMediator boardMediator; + @BeforeEach + void setUp() { + board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); + boardMediator = new BoardMediatorImpl(board); + } + + @Test + @DisplayName("도달 가능한 경우") + void success_1() { + Position from = Position.valueOf(5, 3); + int maxDistance = 1; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + boolean expected = true; + + boolean actual = straightMovement.canReach(from); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("도달 불가능한 경우") + void success_2() { + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + boolean expected = false; + + boolean actual = straightMovement.canReach(from); + + assertThat(actual).isEqualTo(expected); + } + } + +} \ No newline at end of file From 50e0b1f5223478a67054f0dbc79de94daa2093d3 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 15:52:24 +0900 Subject: [PATCH 028/128] =?UTF-8?q?feat(straight-movement):=20=EB=8F=84?= =?UTF-8?q?=EB=8B=AC=20=EC=97=AC=EB=B6=80=20=ED=8C=90=EC=A0=95=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Position.java | 9 ++++ .../janggi/domain/board/BoardMediator.java | 10 ++++ .../domain/board/BoardMediatorImpl.java | 23 ++++++++ .../janggi/domain/movement/Direction.java | 12 ++++- .../java/janggi/domain/movement/Movement.java | 10 ++++ .../domain/movement/StraightMovement.java | 53 +++++++++++++++++++ 6 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/main/java/janggi/domain/board/BoardMediator.java create mode 100644 src/main/java/janggi/domain/board/BoardMediatorImpl.java create mode 100644 src/main/java/janggi/domain/movement/Movement.java create mode 100644 src/main/java/janggi/domain/movement/StraightMovement.java diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 4bf19670c9..b1bc84cf90 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -1,5 +1,6 @@ package janggi.domain; +import janggi.domain.movement.Direction; import java.util.LinkedHashMap; import java.util.Map; @@ -52,4 +53,12 @@ private static void validateColumnRange(final int column) { throw new IllegalArgumentException("열 입력은 1~9을 입력해야 합니다."); } } + + public Position calculateNext(final int distance, final Direction direction) { + final int nextRow = row + direction.getRowDirection() * distance; + final int nextColumn = column + direction.getColumnDirection() * distance; + + return Position.valueOf(Math.clamp(nextRow, MINIMUM_ROW, MAXIMUM_ROW), + Math.clamp(nextColumn, MINIMUM_COLUMN, MAXIMUM_COLUMN)); + } } diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java new file mode 100644 index 0000000000..cd43072992 --- /dev/null +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -0,0 +1,10 @@ +package janggi.domain.board; + +import janggi.domain.Position; +import janggi.domain.piece.Piece; + +public interface BoardMediator { + boolean existsInPosition(Position position); + Piece getPieceInPosition(Position position); + +} diff --git a/src/main/java/janggi/domain/board/BoardMediatorImpl.java b/src/main/java/janggi/domain/board/BoardMediatorImpl.java new file mode 100644 index 0000000000..c064e3ea02 --- /dev/null +++ b/src/main/java/janggi/domain/board/BoardMediatorImpl.java @@ -0,0 +1,23 @@ +package janggi.domain.board; + +import janggi.domain.Position; +import janggi.domain.piece.Piece; + +public class BoardMediatorImpl implements BoardMediator { + + private final Board board; + + public BoardMediatorImpl(final Board board) { + this.board = board; + } + + @Override + public boolean existsInPosition(final Position position) { + return !board.isBlank(position); + } + + @Override + public Piece getPieceInPosition(final Position position) { + return board.findPieceByPosition(position); + } +} diff --git a/src/main/java/janggi/domain/movement/Direction.java b/src/main/java/janggi/domain/movement/Direction.java index 934885513c..89c9e7b0dd 100644 --- a/src/main/java/janggi/domain/movement/Direction.java +++ b/src/main/java/janggi/domain/movement/Direction.java @@ -45,12 +45,20 @@ private static void validateRowDirectionRange(final int rowDirection) { } private static void validateColumnDirectionRange(final int columnDirection) { - if (columnDirection < MINIMUM_COLUMN_DIRECTION || columnDirection > MAXIMUM_COLUMN_DIRECTION) { + if (columnDirection < MINIMUM_COLUMN_DIRECTION + || columnDirection > MAXIMUM_COLUMN_DIRECTION) { throw new IllegalArgumentException(String.format( - "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION)); + "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_COLUMN_DIRECTION, + MAXIMUM_COLUMN_DIRECTION)); } } + public int getRowDirection() { + return rowDirection; + } + public int getColumnDirection() { + return columnDirection; + } } diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java new file mode 100644 index 0000000000..93de7d8e68 --- /dev/null +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -0,0 +1,10 @@ +package janggi.domain.movement; + +import janggi.domain.Position; +import java.util.List; + +public interface Movement { + boolean canReach(Position from); + Position calculateDestination(Position from); + List calculateTraces(Position from); +} diff --git a/src/main/java/janggi/domain/movement/StraightMovement.java b/src/main/java/janggi/domain/movement/StraightMovement.java new file mode 100644 index 0000000000..7da2970881 --- /dev/null +++ b/src/main/java/janggi/domain/movement/StraightMovement.java @@ -0,0 +1,53 @@ +package janggi.domain.movement; + +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import java.util.ArrayList; +import java.util.List; + +public class StraightMovement implements Movement { + private final BoardMediator boardMediator; + private final int maxDistance; + private final Direction direction; + + public StraightMovement(int maxDistance, Direction direction, BoardMediator boardMediator) { + this.maxDistance = maxDistance; + this.direction = direction; + this.boardMediator = boardMediator; + } + + @Override + public boolean canReach(final Position from) { + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + return false; + } + } + return true; + } + + @Override + public Position calculateDestination(final Position from) { + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + return to; + } + } + return from.calculateNext(maxDistance, direction); + } + + @Override + public List calculateTraces(final Position from) { + final List traces = new ArrayList<>(); + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + break; + } + traces.add(to); + } + return traces; + } +} From ccf0c0aebc9a4e6effa00b1bb97415f31851c5de Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 16:00:48 +0900 Subject: [PATCH 029/128] =?UTF-8?q?test(straight-movement):=20=EB=AA=A9?= =?UTF-8?q?=EC=A0=81=EC=A7=80=20=EA=B3=84=EC=82=B0=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 --- .../domain/movement/StraightMovementTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/test/java/janggi/domain/movement/StraightMovementTest.java b/src/test/java/janggi/domain/movement/StraightMovementTest.java index 4c7ff05e76..66e2a328f0 100644 --- a/src/test/java/janggi/domain/movement/StraightMovementTest.java +++ b/src/test/java/janggi/domain/movement/StraightMovementTest.java @@ -59,4 +59,66 @@ void success_2() { } } + @Nested + @DisplayName("목적지 계산 테스트") + class CalculateDestination { + + Board board; + BoardMediator boardMediator; + @BeforeEach + void setUp() { + board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); + boardMediator = new BoardMediatorImpl(board); + } + + @Test + @DisplayName("경로에 아군이 있는 경우") + void success_1() { + board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.RED))); + boardMediator = new BoardMediatorImpl(board); + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Position expected = Position.valueOf(5, 5); + + Position actual = straightMovement.calculateDestination(from); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("경로에 적군이 있는 경우") + void success_2() { + board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); + boardMediator = new BoardMediatorImpl(board); + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Position expected = Position.valueOf(5, 6); + + Position actual = straightMovement.calculateDestination(from); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("경로에 기물이 없는 경우") + void success_3() { + board = new Board(Map.of()); + boardMediator = new BoardMediatorImpl(board); + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Position expected = Position.valueOf(5, 7); + + Position actual = straightMovement.calculateDestination(from); + + assertThat(actual).isEqualTo(expected); + } + + } + } \ No newline at end of file From 280bbc34c3f4bbb0f2dd209912584776fc7946d6 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 16:09:33 +0900 Subject: [PATCH 030/128] =?UTF-8?q?feat(straight-movement):=20=EB=AA=A9?= =?UTF-8?q?=EC=A0=81=EC=A7=80=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Position.java | 15 +++++++++++++++ .../domain/movement/StraightMovement.java | 8 +++++++- .../domain/movement/StraightMovementTest.java | 19 ++++++++++--------- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index b1bc84cf90..6ae552505a 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -3,6 +3,7 @@ import janggi.domain.movement.Direction; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; public final class Position { @@ -23,6 +24,20 @@ public final class Position { private final int row; private final int column; + @Override + public boolean equals(final Object object) { + if (object == null || getClass() != object.getClass()) { + return false; + } + final Position position = (Position) object; + return row == position.row && column == position.column; + } + + @Override + public int hashCode() { + return Objects.hash(row, column); + } + private Position(final int row, final int column) { this.row = row; this.column = column; diff --git a/src/main/java/janggi/domain/movement/StraightMovement.java b/src/main/java/janggi/domain/movement/StraightMovement.java index 7da2970881..b90c4f6b4a 100644 --- a/src/main/java/janggi/domain/movement/StraightMovement.java +++ b/src/main/java/janggi/domain/movement/StraightMovement.java @@ -2,6 +2,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.piece.Piece; import java.util.ArrayList; import java.util.List; @@ -29,10 +30,15 @@ public boolean canReach(final Position from) { @Override public Position calculateDestination(final Position from) { + Piece fromPiece = boardMediator.getPieceInPosition(from); for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { - return to; + Piece toPiece = boardMediator.getPieceInPosition(to); + if (toPiece.belongsToTeam(fromPiece.getTeamType())) { + return from.calculateNext(distance - 1, direction); + } + return from.calculateNext(distance, direction); } } return from.calculateNext(maxDistance, direction); diff --git a/src/test/java/janggi/domain/movement/StraightMovementTest.java b/src/test/java/janggi/domain/movement/StraightMovementTest.java index 66e2a328f0..c9128fc9b1 100644 --- a/src/test/java/janggi/domain/movement/StraightMovementTest.java +++ b/src/test/java/janggi/domain/movement/StraightMovementTest.java @@ -8,8 +8,11 @@ import janggi.domain.board.Board; import janggi.domain.board.BoardMediator; import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Chariot; +import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -63,19 +66,18 @@ void success_2() { @DisplayName("목적지 계산 테스트") class CalculateDestination { - Board board; + Map positionPieceMap = new LinkedHashMap<>(); BoardMediator boardMediator; @BeforeEach void setUp() { - board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); - boardMediator = new BoardMediatorImpl(board); + positionPieceMap.put(Position.valueOf(5, 3), new Chariot(TeamType.RED)); } @Test @DisplayName("경로에 아군이 있는 경우") void success_1() { - board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.RED))); - boardMediator = new BoardMediatorImpl(board); + positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.RED)); + boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); @@ -90,8 +92,8 @@ void success_1() { @Test @DisplayName("경로에 적군이 있는 경우") void success_2() { - board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); - boardMediator = new BoardMediatorImpl(board); + positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.BLUE)); + boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); @@ -106,8 +108,7 @@ void success_2() { @Test @DisplayName("경로에 기물이 없는 경우") void success_3() { - board = new Board(Map.of()); - boardMediator = new BoardMediatorImpl(board); + boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); From 7e3d518d10d0dcc2f1042b71d42c57a07cfcf173 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 16:14:18 +0900 Subject: [PATCH 031/128] =?UTF-8?q?test(straight-movement):=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=9E=90=EC=B7=A8=20=EC=9C=84=EC=B9=98=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B3=84=EC=82=B0=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 --- .../domain/movement/StraightMovementTest.java | 70 ++++++++++++++++++- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StraightMovementTest.java b/src/test/java/janggi/domain/movement/StraightMovementTest.java index c9128fc9b1..b2417aec9e 100644 --- a/src/test/java/janggi/domain/movement/StraightMovementTest.java +++ b/src/test/java/janggi/domain/movement/StraightMovementTest.java @@ -1,8 +1,6 @@ package janggi.domain.movement; -import static janggi.domain.Position.MAXIMUM_ROW; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.Position; import janggi.domain.board.Board; @@ -13,6 +11,7 @@ import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -27,6 +26,7 @@ class CanReach { Board board; BoardMediator boardMediator; + @BeforeEach void setUp() { board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); @@ -68,6 +68,7 @@ class CalculateDestination { Map positionPieceMap = new LinkedHashMap<>(); BoardMediator boardMediator; + @BeforeEach void setUp() { positionPieceMap.put(Position.valueOf(5, 3), new Chariot(TeamType.RED)); @@ -122,4 +123,67 @@ void success_3() { } + @Nested + @DisplayName("경로 자취 계산 테스트") + class CalculateTraces { + + Map positionPieceMap = new LinkedHashMap<>(); + BoardMediator boardMediator; + + @BeforeEach + void setUp() { + positionPieceMap.put(Position.valueOf(5, 3), new Chariot(TeamType.RED)); + } + + @Test + @DisplayName("경로에 아군이 있는 경우") + void success_1() { + positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.RED)); + boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); + + List actual = straightMovement.calculateTraces(from); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 적군이 있는 경우") + void success_2() { + positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.BLUE)); + boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), + Position.valueOf(5, 6)); + + List actual = straightMovement.calculateTraces(from); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 기물이 없는 경우") + void success_3() { + boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Position from = Position.valueOf(5, 3); + int maxDistance = 4; + Direction direction = Direction.valueOf(0, 1); + Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), + Position.valueOf(5, 6), Position.valueOf(5, 7)); + + List actual = straightMovement.calculateTraces(from); + + assertThat(actual).hasSameElementsAs(expected); + } + + } + } \ No newline at end of file From 16f5a0c419ec5c5f160cbaf16f431ecd01f12a1b Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 16:16:07 +0900 Subject: [PATCH 032/128] =?UTF-8?q?feat(straight-movement):=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=9E=90=EC=B7=A8=20=EC=9C=84=EC=B9=98=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/movement/StraightMovement.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/movement/StraightMovement.java b/src/main/java/janggi/domain/movement/StraightMovement.java index b90c4f6b4a..9a7a7d0e49 100644 --- a/src/main/java/janggi/domain/movement/StraightMovement.java +++ b/src/main/java/janggi/domain/movement/StraightMovement.java @@ -46,11 +46,16 @@ public Position calculateDestination(final Position from) { @Override public List calculateTraces(final Position from) { + final Piece fromPiece = boardMediator.getPieceInPosition(from); final List traces = new ArrayList<>(); for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { - break; + Piece toPiece = boardMediator.getPieceInPosition(to); + if (!toPiece.belongsToTeam(fromPiece.getTeamType())) { + traces.add(to); + } + return traces; } traces.add(to); } From fd85740d5909af2c5ef1aebed56314ec2e8cd5f2 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 26 Mar 2026 16:28:54 +0900 Subject: [PATCH 033/128] =?UTF-8?q?refactor(movement):=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=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 --- .../java/janggi/domain/movement/Movement.java | 59 +++++++++++++++-- .../domain/movement/StraightMovement.java | 64 ------------------- ...ghtMovementTest.java => MovementTest.java} | 38 +++++------ 3 files changed, 74 insertions(+), 87 deletions(-) delete mode 100644 src/main/java/janggi/domain/movement/StraightMovement.java rename src/test/java/janggi/domain/movement/{StraightMovementTest.java => MovementTest.java} (78%) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 93de7d8e68..fb5853b696 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -1,10 +1,61 @@ package janggi.domain.movement; import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.piece.Piece; +import java.util.ArrayList; import java.util.List; -public interface Movement { - boolean canReach(Position from); - Position calculateDestination(Position from); - List calculateTraces(Position from); +public class Movement { + private final BoardMediator boardMediator; + private final int maxDistance; + private final Direction direction; + + public Movement(int maxDistance, Direction direction, BoardMediator boardMediator) { + this.maxDistance = maxDistance; + this.direction = direction; + this.boardMediator = boardMediator; + } + + public boolean canReach(final Position from) { + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + return false; + } + } + return true; + } + + public Position calculateDestination(final Position from) { + Piece fromPiece = boardMediator.getPieceInPosition(from); + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + Piece toPiece = boardMediator.getPieceInPosition(to); + if (toPiece.belongsToTeam(fromPiece.getTeamType())) { + return from.calculateNext(distance - 1, direction); + } + return from.calculateNext(distance, direction); + } + } + return from.calculateNext(maxDistance, direction); + } + + public List calculateTraces(final Position from) { + final Piece fromPiece = boardMediator.getPieceInPosition(from); + final List traces = new ArrayList<>(); + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + Piece toPiece = boardMediator.getPieceInPosition(to); + if (!toPiece.belongsToTeam(fromPiece.getTeamType())) { + traces.add(to); + } + return traces; + } + traces.add(to); + } + return traces; + } } diff --git a/src/main/java/janggi/domain/movement/StraightMovement.java b/src/main/java/janggi/domain/movement/StraightMovement.java deleted file mode 100644 index 9a7a7d0e49..0000000000 --- a/src/main/java/janggi/domain/movement/StraightMovement.java +++ /dev/null @@ -1,64 +0,0 @@ -package janggi.domain.movement; - -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; -import janggi.domain.piece.Piece; -import java.util.ArrayList; -import java.util.List; - -public class StraightMovement implements Movement { - private final BoardMediator boardMediator; - private final int maxDistance; - private final Direction direction; - - public StraightMovement(int maxDistance, Direction direction, BoardMediator boardMediator) { - this.maxDistance = maxDistance; - this.direction = direction; - this.boardMediator = boardMediator; - } - - @Override - public boolean canReach(final Position from) { - for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { - return false; - } - } - return true; - } - - @Override - public Position calculateDestination(final Position from) { - Piece fromPiece = boardMediator.getPieceInPosition(from); - for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { - Piece toPiece = boardMediator.getPieceInPosition(to); - if (toPiece.belongsToTeam(fromPiece.getTeamType())) { - return from.calculateNext(distance - 1, direction); - } - return from.calculateNext(distance, direction); - } - } - return from.calculateNext(maxDistance, direction); - } - - @Override - public List calculateTraces(final Position from) { - final Piece fromPiece = boardMediator.getPieceInPosition(from); - final List traces = new ArrayList<>(); - for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { - Piece toPiece = boardMediator.getPieceInPosition(to); - if (!toPiece.belongsToTeam(fromPiece.getTeamType())) { - traces.add(to); - } - return traces; - } - traces.add(to); - } - return traces; - } -} diff --git a/src/test/java/janggi/domain/movement/StraightMovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java similarity index 78% rename from src/test/java/janggi/domain/movement/StraightMovementTest.java rename to src/test/java/janggi/domain/movement/MovementTest.java index b2417aec9e..03d56e032b 100644 --- a/src/test/java/janggi/domain/movement/StraightMovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -18,7 +18,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -class StraightMovementTest { +class MovementTest { @Nested @DisplayName("도달 여부 판정 테스트") @@ -39,10 +39,10 @@ void success_1() { Position from = Position.valueOf(5, 3); int maxDistance = 1; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); boolean expected = true; - boolean actual = straightMovement.canReach(from); + boolean actual = Movement.canReach(from); assertThat(actual).isEqualTo(expected); } @@ -53,10 +53,10 @@ void success_2() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); boolean expected = false; - boolean actual = straightMovement.canReach(from); + boolean actual = Movement.canReach(from); assertThat(actual).isEqualTo(expected); } @@ -82,10 +82,10 @@ void success_1() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); Position expected = Position.valueOf(5, 5); - Position actual = straightMovement.calculateDestination(from); + Position actual = Movement.calculateDestination(from); assertThat(actual).isEqualTo(expected); } @@ -98,10 +98,10 @@ void success_2() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); Position expected = Position.valueOf(5, 6); - Position actual = straightMovement.calculateDestination(from); + Position actual = Movement.calculateDestination(from); assertThat(actual).isEqualTo(expected); } @@ -113,10 +113,10 @@ void success_3() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); Position expected = Position.valueOf(5, 7); - Position actual = straightMovement.calculateDestination(from); + Position actual = Movement.calculateDestination(from); assertThat(actual).isEqualTo(expected); } @@ -143,10 +143,10 @@ void success_1() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); - List actual = straightMovement.calculateTraces(from); + List actual = Movement.calculateTraces(from); assertThat(actual).hasSameElementsAs(expected); } @@ -159,11 +159,11 @@ void success_2() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), - Position.valueOf(5, 6)); + Position.valueOf(5, 6)); - List actual = straightMovement.calculateTraces(from); + List actual = Movement.calculateTraces(from); assertThat(actual).hasSameElementsAs(expected); } @@ -175,11 +175,11 @@ void success_3() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement straightMovement = new StraightMovement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction, boardMediator); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), - Position.valueOf(5, 6), Position.valueOf(5, 7)); + Position.valueOf(5, 6), Position.valueOf(5, 7)); - List actual = straightMovement.calculateTraces(from); + List actual = Movement.calculateTraces(from); assertThat(actual).hasSameElementsAs(expected); } From 3644d3cfcd1b451dd0597f574da9e896d91c4625 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 26 Mar 2026 16:42:13 +0900 Subject: [PATCH 034/128] =?UTF-8?q?test(rule):=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=EC=9E=90=EC=B7=A8=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EA=B3=84=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/RuleWithTracesTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/java/janggi/domain/movement/RuleWithTracesTest.java diff --git a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java new file mode 100644 index 0000000000..16b4654cdb --- /dev/null +++ b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java @@ -0,0 +1,35 @@ +package janggi.domain.movement; + +import static janggi.domain.Position.MAXIMUM_ROW; +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.Position; +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Elephant; +import janggi.domain.team.TeamType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class RuleWithTracesTest { + + Board board; + BoardMediator boardMediator; + + @Test + @DisplayName("이동 가능한 자취 경로 계산 테스트") + public void execute() { + board = new Board(Map.of(Position.valueOf(8, 3), new Elephant(TeamType.BLUE))); + boardMediator = new BoardMediatorImpl(board); + Direction direction = Direction.valueOf(1, 0); + Rule ruleWithTraces = new RuleWithTraces(); + List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), Position.valueOf(8, 3)); + + List actual = ruleWithTraces.execute(List.of(new Movement(MAXIMUM_ROW, direction, boardMediator))); + + assertThat(actual).hasSameElementsAs(expected); + } +} From 25f5c80e26cde7413a3b74ec6aa7a5bd63b04661 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 17:22:52 +0900 Subject: [PATCH 035/128] =?UTF-8?q?test(rule):=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=EC=9E=90=EC=B7=A8=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EA=B3=84=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=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 --- .../janggi/domain/movement/RuleWithTracesTest.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java index 16b4654cdb..dfb3cd3bc6 100644 --- a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java @@ -7,7 +7,9 @@ import janggi.domain.board.Board; import janggi.domain.board.BoardMediator; import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Chariot; import janggi.domain.piece.Elephant; +import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.List; import java.util.Map; @@ -22,13 +24,16 @@ public class RuleWithTracesTest { @Test @DisplayName("이동 가능한 자취 경로 계산 테스트") public void execute() { - board = new Board(Map.of(Position.valueOf(8, 3), new Elephant(TeamType.BLUE))); - boardMediator = new BoardMediatorImpl(board); + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Chariot(TeamType.RED), + Position.valueOf(8, 3), new Elephant(TeamType.BLUE)); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(1, 0); - Rule ruleWithTraces = new RuleWithTraces(); + Rule ruleWithTraces = new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, direction, boardMediator))); List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), Position.valueOf(8, 3)); - List actual = ruleWithTraces.execute(List.of(new Movement(MAXIMUM_ROW, direction, boardMediator))); + List actual = ruleWithTraces.execute(Position.valueOf(5, 3)); assertThat(actual).hasSameElementsAs(expected); } From 34d3805d7241fa75c986c3c04700a3c106e82118 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 17:23:05 +0900 Subject: [PATCH 036/128] =?UTF-8?q?feat(rule):=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=EC=9E=90=EC=B7=A8=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/movement/Rule.java | 8 +++++ .../domain/movement/RuleWithTraces.java | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/main/java/janggi/domain/movement/Rule.java create mode 100644 src/main/java/janggi/domain/movement/RuleWithTraces.java diff --git a/src/main/java/janggi/domain/movement/Rule.java b/src/main/java/janggi/domain/movement/Rule.java new file mode 100644 index 0000000000..a474d56d92 --- /dev/null +++ b/src/main/java/janggi/domain/movement/Rule.java @@ -0,0 +1,8 @@ +package janggi.domain.movement; + +import janggi.domain.Position; +import java.util.List; + +public interface Rule { + List execute(Position from); +} diff --git a/src/main/java/janggi/domain/movement/RuleWithTraces.java b/src/main/java/janggi/domain/movement/RuleWithTraces.java new file mode 100644 index 0000000000..3bed6bf189 --- /dev/null +++ b/src/main/java/janggi/domain/movement/RuleWithTraces.java @@ -0,0 +1,34 @@ +package janggi.domain.movement; + +import janggi.domain.Position; +import java.util.ArrayList; +import java.util.List; + +public class RuleWithTraces implements Rule { + + private final List movementOrder; + + public RuleWithTraces(final List movementOrder) { + this.movementOrder = movementOrder; + } + + @Override + public List execute(Position from) { + final List traces = new ArrayList<>(); + final List movementOrderWithoutLast = getMovementOrderWithoutLast(); + final Movement lastMovement = movementOrder.getLast(); + for (final Movement movement: movementOrderWithoutLast) { + traces.addAll(movement.calculateTraces(from)); + traces.add(movement.calculateDestination(from)); + from = traces.getLast(); + } + traces.addAll(lastMovement.calculateTraces(from)); + return traces; + } + + private List getMovementOrderWithoutLast() { + final List movementOrderWithoutLast = new ArrayList<>(movementOrder); + movementOrderWithoutLast.removeLast(); + return movementOrderWithoutLast; + } +} From 95422988d708e7a8954cabbce37230a0e46a45ba Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 17:41:15 +0900 Subject: [PATCH 037/128] =?UTF-8?q?refactor(movement):=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=8C=80=EC=83=81=20=EA=B8=B0=EB=AC=BC=EC=9D=84=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=A1=9C=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=ED=95=98=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 다음 메서드의 시그니처를 수정했습니다: - calculateDestination - calculateTraces --- src/main/java/janggi/domain/movement/Movement.java | 10 ++++------ src/main/java/janggi/domain/movement/Rule.java | 3 ++- .../java/janggi/domain/movement/RuleWithTraces.java | 11 +++++++---- .../java/janggi/domain/movement/MovementTest.java | 12 ++++++------ .../janggi/domain/movement/RuleWithTracesTest.java | 8 +++++--- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index fb5853b696..8305173a2a 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -27,13 +27,12 @@ public boolean canReach(final Position from) { return true; } - public Position calculateDestination(final Position from) { - Piece fromPiece = boardMediator.getPieceInPosition(from); + public Position calculateDestination(final Position from, final Piece piece) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { Piece toPiece = boardMediator.getPieceInPosition(to); - if (toPiece.belongsToTeam(fromPiece.getTeamType())) { + if (toPiece.belongsToTeam(piece.getTeamType())) { return from.calculateNext(distance - 1, direction); } return from.calculateNext(distance, direction); @@ -42,14 +41,13 @@ public Position calculateDestination(final Position from) { return from.calculateNext(maxDistance, direction); } - public List calculateTraces(final Position from) { - final Piece fromPiece = boardMediator.getPieceInPosition(from); + public List calculateTraces(final Position from, final Piece piece) { final List traces = new ArrayList<>(); for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { Piece toPiece = boardMediator.getPieceInPosition(to); - if (!toPiece.belongsToTeam(fromPiece.getTeamType())) { + if (!toPiece.belongsToTeam(piece.getTeamType())) { traces.add(to); } return traces; diff --git a/src/main/java/janggi/domain/movement/Rule.java b/src/main/java/janggi/domain/movement/Rule.java index a474d56d92..f1a9646639 100644 --- a/src/main/java/janggi/domain/movement/Rule.java +++ b/src/main/java/janggi/domain/movement/Rule.java @@ -1,8 +1,9 @@ package janggi.domain.movement; import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import java.util.List; public interface Rule { - List execute(Position from); + List execute(Position from, BoardMediator boardMediator); } diff --git a/src/main/java/janggi/domain/movement/RuleWithTraces.java b/src/main/java/janggi/domain/movement/RuleWithTraces.java index 3bed6bf189..a8345736b8 100644 --- a/src/main/java/janggi/domain/movement/RuleWithTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithTraces.java @@ -1,6 +1,8 @@ package janggi.domain.movement; import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.piece.Piece; import java.util.ArrayList; import java.util.List; @@ -13,16 +15,17 @@ public RuleWithTraces(final List movementOrder) { } @Override - public List execute(Position from) { + public List execute(Position from, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); final List movementOrderWithoutLast = getMovementOrderWithoutLast(); final Movement lastMovement = movementOrder.getLast(); + final Piece piece = boardMediator.getPieceInPosition(from); for (final Movement movement: movementOrderWithoutLast) { - traces.addAll(movement.calculateTraces(from)); - traces.add(movement.calculateDestination(from)); + traces.addAll(movement.calculateTraces(from, piece)); + traces.add(movement.calculateDestination(from, piece)); from = traces.getLast(); } - traces.addAll(lastMovement.calculateTraces(from)); + traces.addAll(lastMovement.calculateTraces(from, piece)); return traces; } diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 03d56e032b..646906c7bf 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -85,7 +85,7 @@ void success_1() { Movement Movement = new Movement(maxDistance, direction, boardMediator); Position expected = Position.valueOf(5, 5); - Position actual = Movement.calculateDestination(from); + Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from)); assertThat(actual).isEqualTo(expected); } @@ -101,7 +101,7 @@ void success_2() { Movement Movement = new Movement(maxDistance, direction, boardMediator); Position expected = Position.valueOf(5, 6); - Position actual = Movement.calculateDestination(from); + Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from)); assertThat(actual).isEqualTo(expected); } @@ -116,7 +116,7 @@ void success_3() { Movement Movement = new Movement(maxDistance, direction, boardMediator); Position expected = Position.valueOf(5, 7); - Position actual = Movement.calculateDestination(from); + Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from)); assertThat(actual).isEqualTo(expected); } @@ -146,7 +146,7 @@ void success_1() { Movement Movement = new Movement(maxDistance, direction, boardMediator); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); - List actual = Movement.calculateTraces(from); + List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from)); assertThat(actual).hasSameElementsAs(expected); } @@ -163,7 +163,7 @@ void success_2() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6)); - List actual = Movement.calculateTraces(from); + List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from)); assertThat(actual).hasSameElementsAs(expected); } @@ -179,7 +179,7 @@ void success_3() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6), Position.valueOf(5, 7)); - List actual = Movement.calculateTraces(from); + List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from)); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java index dfb3cd3bc6..3a4d91f212 100644 --- a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java @@ -30,10 +30,12 @@ public void execute() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(1, 0); - Rule ruleWithTraces = new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, direction, boardMediator))); - List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), Position.valueOf(8, 3)); + Rule ruleWithTraces = new RuleWithTraces( + List.of(new Movement(MAXIMUM_ROW, direction, boardMediator))); + List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), + Position.valueOf(8, 3)); - List actual = ruleWithTraces.execute(Position.valueOf(5, 3)); + List actual = ruleWithTraces.execute(Position.valueOf(5, 3), boardMediator); assertThat(actual).hasSameElementsAs(expected); } From eb7ca576bdd9bea1a7ccf787b6f01c052a84bc09 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 17:42:20 +0900 Subject: [PATCH 038/128] =?UTF-8?q?test(rule):=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=EB=AA=A9=EC=A0=81=EC=A7=80=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=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 --- .../domain/movement/RuleWithNoTracesTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java diff --git a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java new file mode 100644 index 0000000000..410d1175eb --- /dev/null +++ b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java @@ -0,0 +1,37 @@ +package janggi.domain.movement; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.Position; +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Elephant; +import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class RuleWithNoTracesTest { + + @Test + @DisplayName("이동 가능한 목적지 계산 테스트") + public void execute() { + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED)); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List movementOrder = List.of( + new Movement(1, Direction.valueOf(0, 1), boardMediator), + new Movement(2, Direction.valueOf(-1, 1), boardMediator)); + Rule ruleWithNoTraces = new ruleWithNoTraces(movementOrder); + List expected = List.of(Position.valueOf(3, 6)); + + List actual = ruleWithNoTraces.execute(Position.valueOf(5, 3), boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + +} From ad3f207682419ec64883347b4aac95e1d68c222e Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 18:33:50 +0900 Subject: [PATCH 039/128] =?UTF-8?q?test(rule):=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=EB=AA=A9=EC=A0=81=EC=A7=80=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/RuleWithNoTraces.java | 28 +++++++++++++++++++ .../domain/movement/RuleWithNoTracesTest.java | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/main/java/janggi/domain/movement/RuleWithNoTraces.java diff --git a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java new file mode 100644 index 0000000000..d454787a1d --- /dev/null +++ b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java @@ -0,0 +1,28 @@ +package janggi.domain.movement; + +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.piece.Piece; +import java.util.List; + +public class RuleWithNoTraces implements Rule { + + private final List movementOrder; + + public RuleWithNoTraces(final List movementOrder) { + this.movementOrder = movementOrder; + } + + @Override + public List execute(Position from, final BoardMediator boardMediator) { + final Piece piece = boardMediator.getPieceInPosition(from); + for (final Movement movement : movementOrder) { + if (!movement.canReach(from)) { + return List.of(); + } + from = movement.calculateDestination(from, piece); + } + + return List.of(from); + } +} diff --git a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java index 410d1175eb..3360396ada 100644 --- a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java @@ -26,7 +26,7 @@ public void execute() { List movementOrder = List.of( new Movement(1, Direction.valueOf(0, 1), boardMediator), new Movement(2, Direction.valueOf(-1, 1), boardMediator)); - Rule ruleWithNoTraces = new ruleWithNoTraces(movementOrder); + Rule ruleWithNoTraces = new RuleWithNoTraces(movementOrder); List expected = List.of(Position.valueOf(3, 6)); List actual = ruleWithNoTraces.execute(Position.valueOf(5, 3), boardMediator); From 095976c8e0254831f1787810f410c5d6f974d27e Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 26 Mar 2026 19:33:52 +0900 Subject: [PATCH 040/128] =?UTF-8?q?test:=20board=20mediator=EB=A5=BC=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=A1=9C=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/movement/Movement.java | 10 ++--- .../domain/movement/RuleWithNoTraces.java | 4 +- .../domain/movement/RuleWithTraces.java | 8 ++-- src/main/java/janggi/domain/piece/Cannon.java | 8 ++++ .../java/janggi/domain/piece/Chariot.java | 24 ++++++++++++ .../java/janggi/domain/piece/Elephant.java | 8 ++++ .../java/janggi/domain/piece/General.java | 8 ++++ src/main/java/janggi/domain/piece/Guard.java | 8 ++++ src/main/java/janggi/domain/piece/Horse.java | 8 ++++ src/main/java/janggi/domain/piece/Piece.java | 7 ++++ .../java/janggi/domain/piece/PieceAction.java | 22 +++++++++++ .../java/janggi/domain/piece/Soldier.java | 7 ++++ src/test/java/janggi/domain/ChariotTest.java | 12 +++--- .../janggi/domain/movement/MovementTest.java | 38 +++++++++++-------- .../domain/movement/RuleWithNoTracesTest.java | 6 +-- .../domain/movement/RuleWithTracesTest.java | 8 ++-- 16 files changed, 146 insertions(+), 40 deletions(-) create mode 100644 src/main/java/janggi/domain/piece/PieceAction.java diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 8305173a2a..aa00af2f84 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -7,17 +7,15 @@ import java.util.List; public class Movement { - private final BoardMediator boardMediator; private final int maxDistance; private final Direction direction; - public Movement(int maxDistance, Direction direction, BoardMediator boardMediator) { + public Movement(int maxDistance, Direction direction) { this.maxDistance = maxDistance; this.direction = direction; - this.boardMediator = boardMediator; } - public boolean canReach(final Position from) { + public boolean canReach(final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { @@ -27,7 +25,7 @@ public boolean canReach(final Position from) { return true; } - public Position calculateDestination(final Position from, final Piece piece) { + public Position calculateDestination(final Position from, final Piece piece, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { @@ -41,7 +39,7 @@ public Position calculateDestination(final Position from, final Piece piece) { return from.calculateNext(maxDistance, direction); } - public List calculateTraces(final Position from, final Piece piece) { + public List calculateTraces(final Position from, final Piece piece, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); diff --git a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java index d454787a1d..839868b283 100644 --- a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java @@ -17,10 +17,10 @@ public RuleWithNoTraces(final List movementOrder) { public List execute(Position from, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); for (final Movement movement : movementOrder) { - if (!movement.canReach(from)) { + if (!movement.canReach(from, boardMediator)) { return List.of(); } - from = movement.calculateDestination(from, piece); + from = movement.calculateDestination(from, piece, boardMediator); } return List.of(from); diff --git a/src/main/java/janggi/domain/movement/RuleWithTraces.java b/src/main/java/janggi/domain/movement/RuleWithTraces.java index a8345736b8..5a2b1e9347 100644 --- a/src/main/java/janggi/domain/movement/RuleWithTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithTraces.java @@ -20,12 +20,12 @@ public List execute(Position from, final BoardMediator boardMediator) final List movementOrderWithoutLast = getMovementOrderWithoutLast(); final Movement lastMovement = movementOrder.getLast(); final Piece piece = boardMediator.getPieceInPosition(from); - for (final Movement movement: movementOrderWithoutLast) { - traces.addAll(movement.calculateTraces(from, piece)); - traces.add(movement.calculateDestination(from, piece)); + for (final Movement movement : movementOrderWithoutLast) { + traces.addAll(movement.calculateTraces(from, piece, boardMediator)); + traces.add(movement.calculateDestination(from, piece, boardMediator)); from = traces.getLast(); } - traces.addAll(lastMovement.calculateTraces(from, piece)); + traces.addAll(lastMovement.calculateTraces(from, piece, boardMediator)); return traces; } diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 1ba80aff0d..7a1bbe6b08 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -1,7 +1,10 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public class Cannon implements Piece { @@ -27,4 +30,9 @@ public TeamType getTeamType() { public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + + @Override + public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 57bc8927ee..795d39901a 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -1,11 +1,31 @@ package janggi.domain.piece; +import static janggi.domain.Position.MAXIMUM_COLUMN; +import static janggi.domain.Position.MAXIMUM_ROW; + import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Movement; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleWithTraces; import janggi.domain.team.TeamType; +import java.util.List; public class Chariot implements Piece { private static final PieceType PIECE_TYPE = PieceType.CHARIOT; + private static final PieceAction PIECE_ACTION; + + static { + final List rules = List.of( + new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.valueOf(1, 0)))), + new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.valueOf(-1, 0)))), + new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.valueOf(0, 1)))), + new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.valueOf(0, -1))))); + PIECE_ACTION = new PieceAction(rules); + } private final TeamType teamType; @@ -28,4 +48,8 @@ public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + @Override + public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index ea29fc9895..7973a25665 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -1,7 +1,10 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public class Elephant implements Piece { @@ -27,4 +30,9 @@ public TeamType getTeamType() { public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + + @Override + public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 5e000882d0..9e3a5bf6ed 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -1,7 +1,10 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public class General implements Piece { @@ -27,4 +30,9 @@ public TeamType getTeamType() { public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + + @Override + public List calculateMovablePositions(Position from, BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 262d910796..e6aa97d26d 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -1,7 +1,10 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public class Guard implements Piece { @@ -27,4 +30,9 @@ public TeamType getTeamType() { public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + + @Override + public List calculateMovablePositions(Position from, BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index c7a369df7e..5ccc251ef4 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -1,7 +1,10 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public class Horse implements Piece { @@ -27,4 +30,9 @@ public TeamType getTeamType() { public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + + @Override + public List calculateMovablePositions(Position from, BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index b42e9a644d..64779ef91a 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -1,10 +1,17 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public interface Piece { PieceType getPieceType(); + TeamType getTeamType(); + boolean belongsToTeam(TeamType teamType); + + List calculateMovablePositions(Position from, BoardMediator boardMediator); } diff --git a/src/main/java/janggi/domain/piece/PieceAction.java b/src/main/java/janggi/domain/piece/PieceAction.java new file mode 100644 index 0000000000..22ca58680a --- /dev/null +++ b/src/main/java/janggi/domain/piece/PieceAction.java @@ -0,0 +1,22 @@ +package janggi.domain.piece; + +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Rule; +import java.util.Collection; +import java.util.List; + +public class PieceAction { + private final List rules; + + public PieceAction(List rules) { + this.rules = rules; + } + + public List calculateMovablePositions(BoardMediator boardMediator, Position from) { + return rules.stream() + .map(rule -> rule.execute(from, boardMediator)) + .flatMap(Collection::stream) + .toList(); + } +} diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index cdf3ecf97d..e0b7d937f1 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -1,7 +1,10 @@ package janggi.domain.piece; import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; +import java.util.List; public class Soldier implements Piece { @@ -27,4 +30,8 @@ public boolean belongsToTeam(final TeamType teamType) { return this.teamType == teamType; } + @Override + public List calculateMovablePositions(Position from, BoardMediator boardMediator) { + return List.of(); + } } diff --git a/src/test/java/janggi/domain/ChariotTest.java b/src/test/java/janggi/domain/ChariotTest.java index d2a9dd4a2c..c6635902df 100644 --- a/src/test/java/janggi/domain/ChariotTest.java +++ b/src/test/java/janggi/domain/ChariotTest.java @@ -1,8 +1,10 @@ package janggi.domain; -import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Chariot; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -63,8 +65,8 @@ void test1() { Position.valueOf(6, 3), Position.valueOf(7, 3)); Board board = new Board(positionPieceMap); - Map offeredSelectedPieceMap = board.offerSelectedPieceMap(candidatePositions); - List actual = chariot.calculateMovablePositions(offeredSelectedPieceMap, Position.valueOf(5, 3)); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = chariot.calculateMovablePositions(Position.valueOf(5, 3), boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -82,8 +84,8 @@ void test2() { Position.valueOf(5, 5), Position.valueOf(6, 3)); Board board = new Board(positionPieceMap); - Map offeredSelectedPieceMap = board.offerSelectedPieceMap(candidatePositions); - List actual = chariot.calculateMovablePositions(offeredSelectedPieceMap, Position.valueOf(5, 3)); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = chariot.calculateMovablePositions(Position.valueOf(5, 3), boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 646906c7bf..9ae3606014 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -39,10 +39,10 @@ void success_1() { Position from = Position.valueOf(5, 3); int maxDistance = 1; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); boolean expected = true; - boolean actual = Movement.canReach(from); + boolean actual = Movement.canReach(from, boardMediator); assertThat(actual).isEqualTo(expected); } @@ -53,10 +53,10 @@ void success_2() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); boolean expected = false; - boolean actual = Movement.canReach(from); + boolean actual = Movement.canReach(from, boardMediator); assertThat(actual).isEqualTo(expected); } @@ -82,10 +82,11 @@ void success_1() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 5); - Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from)); + Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -98,10 +99,11 @@ void success_2() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 6); - Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from)); + Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -113,10 +115,11 @@ void success_3() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 7); - Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from)); + Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -143,10 +146,11 @@ void success_1() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); - List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from)); + List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -159,11 +163,12 @@ void success_2() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6)); - List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from)); + List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -175,11 +180,12 @@ void success_3() { Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction, boardMediator); + Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6), Position.valueOf(5, 7)); - List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from)); + List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java index 3360396ada..b8603dc8b1 100644 --- a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java @@ -20,12 +20,12 @@ public class RuleWithNoTracesTest { @DisplayName("이동 가능한 목적지 계산 테스트") public void execute() { Map positionPieceMap = Map.of( - Position.valueOf(5, 3), new Elephant(TeamType.RED)); + Position.valueOf(5, 3), new Elephant(TeamType.RED)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List movementOrder = List.of( - new Movement(1, Direction.valueOf(0, 1), boardMediator), - new Movement(2, Direction.valueOf(-1, 1), boardMediator)); + new Movement(1, Direction.valueOf(0, 1)), + new Movement(2, Direction.valueOf(-1, 1))); Rule ruleWithNoTraces = new RuleWithNoTraces(movementOrder); List expected = List.of(Position.valueOf(3, 6)); diff --git a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java index 3a4d91f212..3a6ec968c0 100644 --- a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java @@ -25,15 +25,15 @@ public class RuleWithTracesTest { @DisplayName("이동 가능한 자취 경로 계산 테스트") public void execute() { Map positionPieceMap = Map.of( - Position.valueOf(5, 3), new Chariot(TeamType.RED), - Position.valueOf(8, 3), new Elephant(TeamType.BLUE)); + Position.valueOf(5, 3), new Chariot(TeamType.RED), + Position.valueOf(8, 3), new Elephant(TeamType.BLUE)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(1, 0); Rule ruleWithTraces = new RuleWithTraces( - List.of(new Movement(MAXIMUM_ROW, direction, boardMediator))); + List.of(new Movement(MAXIMUM_ROW, direction))); List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), - Position.valueOf(8, 3)); + Position.valueOf(8, 3)); List actual = ruleWithTraces.execute(Position.valueOf(5, 3), boardMediator); From 26f7d5bca4d4afcd62155be58164983f7b99fd8a Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 26 Mar 2026 19:40:23 +0900 Subject: [PATCH 041/128] =?UTF-8?q?feat(chariot):=20=EC=B0=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Chariot.java | 2 +- src/main/java/janggi/domain/piece/PieceAction.java | 2 +- src/test/java/janggi/domain/ChariotTest.java | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 795d39901a..3acc561195 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -50,6 +50,6 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return List.of(); + return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } } diff --git a/src/main/java/janggi/domain/piece/PieceAction.java b/src/main/java/janggi/domain/piece/PieceAction.java index 22ca58680a..d9dfde8e3a 100644 --- a/src/main/java/janggi/domain/piece/PieceAction.java +++ b/src/main/java/janggi/domain/piece/PieceAction.java @@ -13,7 +13,7 @@ public PieceAction(List rules) { this.rules = rules; } - public List calculateMovablePositions(BoardMediator boardMediator, Position from) { + public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return rules.stream() .map(rule -> rule.execute(from, boardMediator)) .flatMap(Collection::stream) diff --git a/src/test/java/janggi/domain/ChariotTest.java b/src/test/java/janggi/domain/ChariotTest.java index c6635902df..95c486447e 100644 --- a/src/test/java/janggi/domain/ChariotTest.java +++ b/src/test/java/janggi/domain/ChariotTest.java @@ -55,10 +55,10 @@ void setUp() { @DisplayName("차는 적군을 뛰어넘어 갈 수 없다.") void test1() { positionPieceMap.put(Position.valueOf(5, 3), chariot); - positionPieceMap.put(Position.valueOf(5, 1), ally1); - positionPieceMap.put(Position.valueOf(3, 3), ally2); - positionPieceMap.put(Position.valueOf(5, 6), ally3); - positionPieceMap.put(Position.valueOf(7, 3), ally4); + positionPieceMap.put(Position.valueOf(5, 1), enemy1); + positionPieceMap.put(Position.valueOf(3, 3), enemy2); + positionPieceMap.put(Position.valueOf(5, 6), enemy3); + positionPieceMap.put(Position.valueOf(7, 3), enemy4); List expected = List.of(Position.valueOf(3, 3), Position.valueOf(4, 3), Position.valueOf(5, 1), Position.valueOf(5, 2), Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6), From 9e9ad837dfbaf3f21571a1d2682e748579ea2cdb Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 20:09:47 +0900 Subject: [PATCH 042/128] =?UTF-8?q?test(cannon):=20=ED=8F=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=ED=85=8C?= =?UTF-8?q?=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/janggi/domain/CannonTest.java | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/test/java/janggi/domain/CannonTest.java diff --git a/src/test/java/janggi/domain/CannonTest.java b/src/test/java/janggi/domain/CannonTest.java new file mode 100644 index 0000000000..5bcb0431f5 --- /dev/null +++ b/src/test/java/janggi/domain/CannonTest.java @@ -0,0 +1,103 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Cannon; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class CannonTest { + + @Nested + @DisplayName("이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece cannon; + static Piece allySoldier; + static Piece allyCannon; + static Piece enemySoldier; + static Piece enemyCannon; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + cannon = new Cannon(TeamType.RED); + enemySoldier = new Soldier(TeamType.BLUE); + enemyCannon = new Cannon(TeamType.BLUE); + allySoldier = new Soldier(TeamType.BLUE); + allyCannon = new Cannon(TeamType.RED); + } + + @Test + @DisplayName("포는 기물을 뛰어 넘어서 이동할 수 있다.") + void success_1() { + positionPieceMap = Map.of( + Position.valueOf(6, 7), cannon, + Position.valueOf(6, 5), enemySoldier, + Position.valueOf(7, 7), allySoldier); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List expected = List.of( + Position.valueOf(6, 1), + Position.valueOf(6, 2), + Position.valueOf(6, 3), + Position.valueOf(6, 4), + Position.valueOf(8, 7), + Position.valueOf(9, 7), + Position.valueOf(10, 7)); + + List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("포는 포를 넘을 수 없다.") + void success_2() { + positionPieceMap = Map.of( + Position.valueOf(6, 7), cannon, + Position.valueOf(4, 7), enemySoldier, + Position.valueOf(6, 5), enemyCannon, + Position.valueOf(9, 7), allyCannon); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List expected = List.of( + Position.valueOf(1, 7), + Position.valueOf(2, 7), + Position.valueOf(3, 7)); + + List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("포는 포를 잡을 수 없다.") + void success_3() { + positionPieceMap = Map.of( + Position.valueOf(6, 7), cannon, + Position.valueOf(6, 3), enemyCannon, + Position.valueOf(6, 4), allySoldier); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List expected = List.of(); + + List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} From 3d8d512ae828e5fdaf745bd8f8238e692b07cf86 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Thu, 26 Mar 2026 21:40:49 +0900 Subject: [PATCH 043/128] =?UTF-8?q?feat(cannon):=20=ED=8F=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=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 --- .../janggi/domain/movement/Direction.java | 1 + .../java/janggi/domain/movement/Movement.java | 19 +++++++- .../janggi/domain/movement/RuleOfCannon.java | 45 +++++++++++++++++++ src/main/java/janggi/domain/piece/Cannon.java | 21 ++++++++- .../java/janggi/domain/piece/Chariot.java | 6 +++ .../java/janggi/domain/piece/Elephant.java | 6 +++ .../java/janggi/domain/piece/General.java | 6 +++ src/main/java/janggi/domain/piece/Guard.java | 6 +++ src/main/java/janggi/domain/piece/Horse.java | 6 +++ src/main/java/janggi/domain/piece/Piece.java | 2 + .../java/janggi/domain/piece/Soldier.java | 6 +++ .../janggi/domain/movement/MovementTest.java | 34 ++++++++------ .../domain/movement/RuleOfCannonTest.java | 45 +++++++++++++++++++ 13 files changed, 186 insertions(+), 17 deletions(-) create mode 100644 src/main/java/janggi/domain/movement/RuleOfCannon.java create mode 100644 src/test/java/janggi/domain/movement/RuleOfCannonTest.java diff --git a/src/main/java/janggi/domain/movement/Direction.java b/src/main/java/janggi/domain/movement/Direction.java index 89c9e7b0dd..c11ea92017 100644 --- a/src/main/java/janggi/domain/movement/Direction.java +++ b/src/main/java/janggi/domain/movement/Direction.java @@ -2,6 +2,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.stream.IntStream; public final class Direction { diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index aa00af2f84..d8002d1f49 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -7,6 +7,7 @@ import java.util.List; public class Movement { + private final int maxDistance; private final Direction direction; @@ -15,6 +16,7 @@ public Movement(int maxDistance, Direction direction) { this.direction = direction; } + // 최대 거리로 도달할 수 있는 경우 true, 아니라면 false. public boolean canReach(final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); @@ -39,13 +41,26 @@ public Position calculateDestination(final Position from, final Piece piece, fin return from.calculateNext(maxDistance, direction); } - public List calculateTraces(final Position from, final Piece piece, final BoardMediator boardMediator) { + public Position calculateBlockedPosition(final Position from, final Piece piece, final BoardMediator boardMediator) { + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (boardMediator.existsInPosition(to)) { + return from.calculateNext(distance, direction); + } + } + return from.calculateNext(maxDistance, direction); + } + + // 이동 가능한 경로의 자취 위치 리스트를 반환한다. + public List calculateTraces(final Position from, final Piece piece, + final BoardMediator boardMediator) { final List traces = new ArrayList<>(); for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { Piece toPiece = boardMediator.getPieceInPosition(to); - if (!toPiece.belongsToTeam(piece.getTeamType())) { + if (!toPiece.belongsToTeam(piece.getTeamType()) && piece.canKill( + toPiece.getPieceType())) { traces.add(to); } return traces; diff --git a/src/main/java/janggi/domain/movement/RuleOfCannon.java b/src/main/java/janggi/domain/movement/RuleOfCannon.java new file mode 100644 index 0000000000..6f23ab776d --- /dev/null +++ b/src/main/java/janggi/domain/movement/RuleOfCannon.java @@ -0,0 +1,45 @@ +package janggi.domain.movement; + +import static janggi.domain.Position.MAXIMUM_ROW; + +import janggi.domain.PieceType; +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.piece.Piece; +import java.util.ArrayList; +import java.util.List; + +public class RuleOfCannon implements Rule { + + private final List movementOrder; + + public RuleOfCannon(final Direction direction) { + this.movementOrder = generateMovementOrder(direction); + } + + private List generateMovementOrder(final Direction direction) { + return List.of( + new Movement(MAXIMUM_ROW, direction), + new Movement(MAXIMUM_ROW, direction)); + } + + @Override + public List execute(Position from, final BoardMediator boardMediator) { + final Movement firstMovement = movementOrder.getFirst(); + final Movement secondMovement = movementOrder.getLast(); + final Piece piece = boardMediator.getPieceInPosition(from); + + // 포다리로 이동 + from = firstMovement.calculateBlockedPosition(from, piece, boardMediator); + + // 포다리로 판정된 위치에 실제로는 기물이 없거나 위치에 포가 존재하는 경우 이동 불가능 + if (!boardMediator.existsInPosition(from) + || boardMediator.getPieceInPosition(from).getPieceType() == PieceType.CANNON) { + return List.of(); + } + + final List traces = new ArrayList<>( + secondMovement.calculateTraces(from, piece, boardMediator)); + return traces; + } +} diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 7a1bbe6b08..769a2489cf 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -3,12 +3,26 @@ import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleOfCannon; import janggi.domain.team.TeamType; import java.util.List; public class Cannon implements Piece { private static final PieceType PIECE_TYPE = PieceType.CANNON; + private static final PieceAction PIECE_ACTION; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(PieceType.CANNON); + + static { + final List rules = List.of( + new RuleOfCannon(Direction.valueOf(1, 0)), + new RuleOfCannon(Direction.valueOf(-1, 0)), + new RuleOfCannon(Direction.valueOf(0, 1)), + new RuleOfCannon(Direction.valueOf(0, -1))); + PIECE_ACTION = new PieceAction(rules); + } private final TeamType teamType; @@ -33,6 +47,11 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return List.of(); + return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 3acc561195..565d87ce2a 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -17,6 +17,7 @@ public class Chariot implements Piece { private static final PieceType PIECE_TYPE = PieceType.CHARIOT; private static final PieceAction PIECE_ACTION; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List rules = List.of( @@ -52,4 +53,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 7973a25665..f6ed641ef3 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -9,6 +9,7 @@ public class Elephant implements Piece { private static final PieceType PIECE_TYPE = PieceType.ELEPHANT; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(); private final TeamType teamType; @@ -35,4 +36,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return List.of(); } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 9e3a5bf6ed..169b4daad4 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -9,6 +9,7 @@ public class General implements Piece { private static final PieceType PIECE_TYPE = PieceType.GENERAL; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(); private final TeamType teamType; @@ -35,4 +36,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return List.of(); } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index e6aa97d26d..6aa97797fd 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -9,6 +9,7 @@ public class Guard implements Piece { private static final PieceType PIECE_TYPE = PieceType.GUARD; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(); private final TeamType teamType; @@ -35,4 +36,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return List.of(); } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 5ccc251ef4..e09d7b12fe 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -9,6 +9,7 @@ public class Horse implements Piece { private static final PieceType PIECE_TYPE = PieceType.HORSE; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(); private final TeamType teamType; @@ -35,4 +36,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return List.of(); } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 64779ef91a..893df50f49 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -14,4 +14,6 @@ public interface Piece { boolean belongsToTeam(TeamType teamType); List calculateMovablePositions(Position from, BoardMediator boardMediator); + + boolean canKill(PieceType pieceType); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index e0b7d937f1..aed4d64cff 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -9,6 +9,7 @@ public class Soldier implements Piece { private static final PieceType PIECE_TYPE = PieceType.SOLDIER; + private static final List UNCATCHABLE_PIECE_TYPES = List.of(); private final TeamType teamType; public Soldier(final TeamType teamType) { @@ -34,4 +35,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return List.of(); } + + @Override + public boolean canKill(final PieceType pieceType) { + return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + } } diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 9ae3606014..80c19ac03d 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -85,8 +85,9 @@ void success_1() { Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 5); - Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from), - boardMediator); + Position actual = Movement.calculateDestination(from, + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -102,8 +103,9 @@ void success_2() { Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 6); - Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from), - boardMediator); + Position actual = Movement.calculateDestination(from, + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -118,8 +120,9 @@ void success_3() { Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 7); - Position actual = Movement.calculateDestination(from, boardMediator.getPieceInPosition(from), - boardMediator); + Position actual = Movement.calculateDestination(from, + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -149,8 +152,9 @@ void success_1() { Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); - List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from), - boardMediator); + List actual = Movement.calculateTraces(from, + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -165,10 +169,11 @@ void success_2() { Direction direction = Direction.valueOf(0, 1); Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), - Position.valueOf(5, 6)); + Position.valueOf(5, 6)); - List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from), - boardMediator); + List actual = Movement.calculateTraces(from, + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -182,10 +187,11 @@ void success_3() { Direction direction = Direction.valueOf(0, 1); Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), - Position.valueOf(5, 6), Position.valueOf(5, 7)); + Position.valueOf(5, 6), Position.valueOf(5, 7)); - List actual = Movement.calculateTraces(from, boardMediator.getPieceInPosition(from), - boardMediator); + List actual = Movement.calculateTraces(from, + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java b/src/test/java/janggi/domain/movement/RuleOfCannonTest.java new file mode 100644 index 0000000000..2dfa7d3526 --- /dev/null +++ b/src/test/java/janggi/domain/movement/RuleOfCannonTest.java @@ -0,0 +1,45 @@ +package janggi.domain.movement; + +import static janggi.domain.Position.MAXIMUM_ROW; +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.Position; +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Cannon; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class RuleOfCannonTest { + + + @Nested + @DisplayName("이동 가능한 목적지 계산 테스트") + class Execute { + + @Test + @DisplayName("이동 경로에 죽일 수 없는 기물이 있는 경우") + void success() { + Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); + positionPieceMap.put(Position.valueOf(6, 4), new Soldier(TeamType.RED)); + positionPieceMap.put(Position.valueOf(6, 7), new Cannon(TeamType.RED)); + BoardMediator boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Position from = Position.valueOf(6, 7); + Rule ruleOfCannon = new RuleOfCannon(Direction.valueOf(0, -1)); + List expected = List.of(Position.valueOf(6, 3)); + + List actual = ruleOfCannon.execute(from, boardMediator); + + assertThat(actual).isEqualTo(expected); + } + } +} From c4ae3c994de6ddbac5c9040871dbd94b31e8c23b Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 15:10:43 +0900 Subject: [PATCH 044/128] =?UTF-8?q?test(elephant):=20=EC=83=81=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=ED=85=8C?= =?UTF-8?q?=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/janggi/domain/ElephantTest.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/test/java/janggi/domain/ElephantTest.java diff --git a/src/test/java/janggi/domain/ElephantTest.java b/src/test/java/janggi/domain/ElephantTest.java new file mode 100644 index 0000000000..b27988024f --- /dev/null +++ b/src/test/java/janggi/domain/ElephantTest.java @@ -0,0 +1,101 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Elephant; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class ElephantTest { + + @Nested + @DisplayName("이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece elephant; + static Piece enemy1; + static Piece enemy2; + static Piece enemy3; + static Piece enemy4; + static Piece ally1; + static Piece ally2; + static Piece ally3; + static Piece ally4; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + elephant = new Elephant(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy3 = new Soldier(TeamType.BLUE); + enemy4 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + ally3 = new Soldier(TeamType.RED); + ally4 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap(); + } + + @Test + @DisplayName("상은 기물을 뛰어넘을 수 없다.") + void test1() { + positionPieceMap.put(Position.valueOf(6, 4), elephant); + positionPieceMap.put(Position.valueOf(3, 1), enemy1); + positionPieceMap.put(Position.valueOf(5, 4), enemy2); + positionPieceMap.put(Position.valueOf(7, 4), enemy3); + positionPieceMap.put(Position.valueOf(5, 6), ally1); + positionPieceMap.put(Position.valueOf(8, 1), ally2); + positionPieceMap.put(Position.valueOf(8, 7), ally3); + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = elephant.calculateMovablePositions(Position.valueOf(6, 4), boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("상은 직선 한 칸, 대각선 두 칸을 가서 기물을 잡을 수 있다.") + void test2() { + positionPieceMap.put(Position.valueOf(6, 4), elephant); + positionPieceMap.put(Position.valueOf(3, 2), enemy1); + positionPieceMap.put(Position.valueOf(4, 7), enemy2); + List expected = List.of(Position.valueOf(3, 2), Position.valueOf(3, 6), Position.valueOf(4, 1), + Position.valueOf(4, 7), Position.valueOf(8, 1), Position.valueOf(8, 7), Position.valueOf(9, 2), + Position.valueOf(9, 6)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = elephant.calculateMovablePositions(Position.valueOf(6, 4), boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("상은 장기판 밖으로 이동할 수 없다.") + void test3() { + positionPieceMap.put(Position.valueOf(6, 2), elephant); + List expected = List.of(Position.valueOf(3, 4), Position.valueOf(4, 5), Position.valueOf(8, 5), + Position.valueOf(9, 4)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = elephant.calculateMovablePositions(Position.valueOf(6, 2), boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} From 21b4dfcb72e8e72327c1c3252831de4fe0eb9cc5 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 16:13:59 +0900 Subject: [PATCH 045/128] =?UTF-8?q?feat(movement):=20=EB=8F=84=EB=8B=AC=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=ED=8C=90=EC=A0=95=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 도달 가능 여부 판정 기능을 다음의 2가지 기능으로 분리했습니다: - 잡기 여부 판정 기능 - 장애물 여부 판정 기능 --- .../java/janggi/domain/movement/Movement.java | 25 ++++- .../janggi/domain/movement/MovementTest.java | 97 ++++++++++++++++--- 2 files changed, 101 insertions(+), 21 deletions(-) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index d8002d1f49..8e50f20832 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -16,8 +16,21 @@ public Movement(int maxDistance, Direction direction) { this.direction = direction; } - // 최대 거리로 도달할 수 있는 경우 true, 아니라면 false. - public boolean canReach(final Position from, final BoardMediator boardMediator) { + public boolean canKill(final Piece me, final Position from, final BoardMediator boardMediator) { + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = from.calculateNext(distance, direction); + if (!boardMediator.existsInPosition(to)) { + return true; + } + Piece target = boardMediator.getPieceInPosition(to); + if (me.canKill(target)) { + return true; + } + } + return false; + } + + public boolean isBlocked(final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { @@ -27,7 +40,8 @@ public boolean canReach(final Position from, final BoardMediator boardMediator) return true; } - public Position calculateDestination(final Position from, final Piece piece, final BoardMediator boardMediator) { + public Position calculateDestination(final Position from, final Piece piece, + final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { @@ -41,7 +55,8 @@ public Position calculateDestination(final Position from, final Piece piece, fin return from.calculateNext(maxDistance, direction); } - public Position calculateBlockedPosition(final Position from, final Piece piece, final BoardMediator boardMediator) { + public Position calculateBlockedPosition(final Position from, final Piece piece, + final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { @@ -60,7 +75,7 @@ public List calculateTraces(final Position from, final Piece piece, if (boardMediator.existsInPosition(to)) { Piece toPiece = boardMediator.getPieceInPosition(to); if (!toPiece.belongsToTeam(piece.getTeamType()) && piece.canKill( - toPiece.getPieceType())) { + toPiece)) { traces.add(to); } return traces; diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 80c19ac03d..1551150f1f 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -21,42 +21,107 @@ class MovementTest { @Nested - @DisplayName("도달 여부 판정 테스트") - class CanReach { + @DisplayName("잡기 여부 판정 테스트") + class CanKill { - Board board; - BoardMediator boardMediator; + Position from; + Piece me; + Map positionPieceMap; @BeforeEach void setUp() { - board = new Board(Map.of(Position.valueOf(5, 6), new Soldier(TeamType.BLUE))); - boardMediator = new BoardMediatorImpl(board); + from = Position.valueOf(5, 3); + me = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(from, me); } @Test - @DisplayName("도달 가능한 경우") + @DisplayName("대상이 적군인 경우") void success_1() { - Position from = Position.valueOf(5, 3); - int maxDistance = 1; + positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction); + Movement Movement = new Movement(1, direction); boolean expected = true; - boolean actual = Movement.canReach(from, boardMediator); + boolean actual = Movement.canKill(me, from, boardMediator); assertThat(actual).isEqualTo(expected); } @Test - @DisplayName("도달 불가능한 경우") + @DisplayName("대상이 아군인 경우") void success_2() { - Position from = Position.valueOf(5, 3); - int maxDistance = 4; + positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.RED)); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(0, 1); - Movement Movement = new Movement(maxDistance, direction); + Movement Movement = new Movement(1, direction); + boolean expected = false; + + boolean actual = Movement.canKill(me, from, boardMediator); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("대상이 없는 경우") + void success_3() { + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + Direction direction = Direction.valueOf(0, 1); + Movement Movement = new Movement(1, direction); + boolean expected = true; + + boolean actual = Movement.canKill(me, from, boardMediator); + + assertThat(actual).isEqualTo(expected); + } + } + + @Nested + @DisplayName("장애물 여부 판정 테스트") + class IsBlocked { + + Position from; + Piece me; + Map positionPieceMap; + + @BeforeEach + void setUp() { + from = Position.valueOf(5, 3); + me = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(from, me); + } + + @Test + @DisplayName("기물이 없는 경우") + void success_1() { + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + Direction direction = Direction.valueOf(0, 1); + Movement Movement = new Movement(1, direction); + boolean expected = true; + + boolean actual = Movement.isBlocked(from, boardMediator); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("기물이 있는 경우") + void success_2() { + positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + Direction direction = Direction.valueOf(0, 1); + Movement Movement = new Movement(1, direction); boolean expected = false; - boolean actual = Movement.canReach(from, boardMediator); + boolean actual = Movement.isBlocked(from, boardMediator); assertThat(actual).isEqualTo(expected); } From 47918a8d2bad0367fbf8530da9fee1c6c39709f5 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 17:50:47 +0900 Subject: [PATCH 046/128] =?UTF-8?q?feat(elephant):=20=EC=83=81=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Position.java | 8 +++ .../java/janggi/domain/movement/Movement.java | 8 ++- .../domain/movement/RuleWithNoTraces.java | 18 +++++-- src/main/java/janggi/domain/piece/Cannon.java | 4 +- .../java/janggi/domain/piece/Chariot.java | 4 +- .../java/janggi/domain/piece/Elephant.java | 54 +++++++++++++++++-- .../java/janggi/domain/piece/General.java | 4 +- src/main/java/janggi/domain/piece/Guard.java | 4 +- src/main/java/janggi/domain/piece/Horse.java | 4 +- src/main/java/janggi/domain/piece/Piece.java | 2 +- .../java/janggi/domain/piece/Soldier.java | 4 +- src/test/java/janggi/domain/ElephantTest.java | 21 ++++---- .../janggi/domain/movement/MovementTest.java | 4 +- 13 files changed, 105 insertions(+), 34 deletions(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 6ae552505a..8baf1c9496 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -69,6 +69,14 @@ private static void validateColumnRange(final int column) { } } + public boolean checkNextBound(final int distance, final Direction direction) { + final int nextRow = row + direction.getRowDirection() * distance; + final int nextColumn = column + direction.getColumnDirection() * distance; + + return nextRow >= MINIMUM_ROW && nextRow <= MAXIMUM_ROW && nextColumn >= MINIMUM_COLUMN + && nextColumn <= MAXIMUM_COLUMN; + } + public Position calculateNext(final int distance, final Direction direction) { final int nextRow = row + direction.getRowDirection() * distance; final int nextColumn = column + direction.getColumnDirection() * distance; diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 8e50f20832..3d87828613 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -16,6 +16,10 @@ public Movement(int maxDistance, Direction direction) { this.direction = direction; } + public boolean canMove(final Position from) { + return from.checkNextBound(maxDistance, direction); + } + public boolean canKill(final Piece me, final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); @@ -34,10 +38,10 @@ public boolean isBlocked(final Position from, final BoardMediator boardMediator) for (int distance = 1; distance <= maxDistance; distance++) { Position to = from.calculateNext(distance, direction); if (boardMediator.existsInPosition(to)) { - return false; + return true; } } - return true; + return false; } public Position calculateDestination(final Position from, final Piece piece, diff --git a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java index 839868b283..73467f4f16 100644 --- a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; +import java.util.ArrayList; import java.util.List; public class RuleWithNoTraces implements Rule { @@ -16,13 +17,24 @@ public RuleWithNoTraces(final List movementOrder) { @Override public List execute(Position from, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); - for (final Movement movement : movementOrder) { - if (!movement.canReach(from, boardMediator)) { + final List movementOrderWithoutLast = getMovementOrderWithoutLast(); + final Movement lastMovement = movementOrder.getLast(); + for (final Movement movement : movementOrderWithoutLast) { + if (!movement.canMove(from) || movement.isBlocked(from, boardMediator)) { return List.of(); } from = movement.calculateDestination(from, piece, boardMediator); } + if (lastMovement.canMove(from) && lastMovement.canKill(piece, from, boardMediator)) { + from = lastMovement.calculateBlockedPosition(from, piece, boardMediator); + return List.of(from); + } + return List.of(); + } - return List.of(from); + private List getMovementOrderWithoutLast() { + final List movementOrderWithoutLast = new ArrayList<>(movementOrder); + movementOrderWithoutLast.removeLast(); + return movementOrderWithoutLast; } } diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 769a2489cf..e681845864 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -51,7 +51,7 @@ public List calculateMovablePositions(final Position from, final Board } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 565d87ce2a..de12330912 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -55,7 +55,7 @@ public List calculateMovablePositions(final Position from, final Board } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index f6ed641ef3..245c3639a1 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -3,14 +3,58 @@ import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Movement; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleWithNoTraces; import janggi.domain.team.TeamType; import java.util.List; public class Elephant implements Piece { private static final PieceType PIECE_TYPE = PieceType.ELEPHANT; + private static final PieceAction PIECE_ACTION; private static final List UNCATCHABLE_PIECE_TYPES = List.of(); + static { + final List rules = List.of( + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, 1)), + new Movement(1, Direction.valueOf(-1, 1)), + new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, 1)), + new Movement(1, Direction.valueOf(1, 1)), + new Movement(1, Direction.valueOf(1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(-1, 0)), + new Movement(1, Direction.valueOf(-1, 1)), + new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(-1, 0)), + new Movement(1, Direction.valueOf(-1, -1)), + new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, -1)), + new Movement(1, Direction.valueOf(-1, -1)), + new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, -1)), + new Movement(1, Direction.valueOf(1, -1)), + new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(1, 0)), + new Movement(1, Direction.valueOf(1, -1)), + new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(1, 0)), + new Movement(1, Direction.valueOf(1, 1)), + new Movement(1, Direction.valueOf(1, 1))) + )); + + PIECE_ACTION = new PieceAction(rules); + } + private final TeamType teamType; public Elephant(final TeamType teamType) { @@ -33,12 +77,14 @@ public boolean belongsToTeam(final TeamType teamType) { } @Override - public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return List.of(); + public List calculateMovablePositions(final Position from, + final BoardMediator boardMediator) { + return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( + teamType); } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 169b4daad4..39c4b3e755 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -38,7 +38,7 @@ public List calculateMovablePositions(Position from, BoardMediator boa } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 6aa97797fd..35c37ab972 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -38,7 +38,7 @@ public List calculateMovablePositions(Position from, BoardMediator boa } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index e09d7b12fe..1bf901b655 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -38,7 +38,7 @@ public List calculateMovablePositions(Position from, BoardMediator boa } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 893df50f49..2e5583d1e8 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -15,5 +15,5 @@ public interface Piece { List calculateMovablePositions(Position from, BoardMediator boardMediator); - boolean canKill(PieceType pieceType); + boolean canKill(Piece target); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index aed4d64cff..42ee2b64e7 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -37,7 +37,7 @@ public List calculateMovablePositions(Position from, BoardMediator boa } @Override - public boolean canKill(final PieceType pieceType) { - return !UNCATCHABLE_PIECE_TYPES.contains(pieceType); + public boolean canKill(final Piece target) { + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/test/java/janggi/domain/ElephantTest.java b/src/test/java/janggi/domain/ElephantTest.java index b27988024f..dc075dfa63 100644 --- a/src/test/java/janggi/domain/ElephantTest.java +++ b/src/test/java/janggi/domain/ElephantTest.java @@ -52,12 +52,12 @@ void setUp() { @DisplayName("상은 기물을 뛰어넘을 수 없다.") void test1() { positionPieceMap.put(Position.valueOf(6, 4), elephant); - positionPieceMap.put(Position.valueOf(3, 1), enemy1); - positionPieceMap.put(Position.valueOf(5, 4), enemy2); - positionPieceMap.put(Position.valueOf(7, 4), enemy3); - positionPieceMap.put(Position.valueOf(5, 6), ally1); - positionPieceMap.put(Position.valueOf(8, 1), ally2); - positionPieceMap.put(Position.valueOf(8, 7), ally3); + positionPieceMap.put(Position.valueOf(4, 1), ally1); + positionPieceMap.put(Position.valueOf(5, 4), enemy1); + positionPieceMap.put(Position.valueOf(7, 4), ally2); + positionPieceMap.put(Position.valueOf(5, 6), ally3); + positionPieceMap.put(Position.valueOf(8, 1), ally4); + positionPieceMap.put(Position.valueOf(7, 6), enemy2); List expected = List.of(); Board board = new Board(positionPieceMap); @@ -87,13 +87,14 @@ void test2() { @Test @DisplayName("상은 장기판 밖으로 이동할 수 없다.") void test3() { - positionPieceMap.put(Position.valueOf(6, 2), elephant); - List expected = List.of(Position.valueOf(3, 4), Position.valueOf(4, 5), Position.valueOf(8, 5), - Position.valueOf(9, 4)); + positionPieceMap.put(Position.valueOf(1, 1), elephant); + positionPieceMap.put(Position.valueOf(1, 2), ally1); + positionPieceMap.put(Position.valueOf(2, 1), ally3); + List expected = List.of(); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = elephant.calculateMovablePositions(Position.valueOf(6, 2), boardMediator); + List actual = elephant.calculateMovablePositions(Position.valueOf(1, 1), boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 1551150f1f..e6e7ecfd47 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -104,7 +104,7 @@ void success_1() { BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(0, 1); Movement Movement = new Movement(1, direction); - boolean expected = true; + boolean expected = false; boolean actual = Movement.isBlocked(from, boardMediator); @@ -119,7 +119,7 @@ void success_2() { BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.valueOf(0, 1); Movement Movement = new Movement(1, direction); - boolean expected = false; + boolean expected = true; boolean actual = Movement.isBlocked(from, boardMediator); From 8c8ec8595340f7143e65c131ce0a662d53dc9042 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 17:57:49 +0900 Subject: [PATCH 047/128] =?UTF-8?q?test(horse):=20=EB=A7=88=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=ED=85=8C?= =?UTF-8?q?=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/janggi/domain/HorseTest.java | 104 +++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/test/java/janggi/domain/HorseTest.java diff --git a/src/test/java/janggi/domain/HorseTest.java b/src/test/java/janggi/domain/HorseTest.java new file mode 100644 index 0000000000..16d399cfa2 --- /dev/null +++ b/src/test/java/janggi/domain/HorseTest.java @@ -0,0 +1,104 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Horse; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class HorseTest { + + @Nested + @DisplayName("이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece horse; + static Piece enemy1; + static Piece enemy2; + static Piece enemy3; + static Piece enemy4; + static Piece ally1; + static Piece ally2; + static Piece ally3; + static Piece ally4; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + horse = new Horse(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy3 = new Soldier(TeamType.BLUE); + enemy4 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + ally3 = new Soldier(TeamType.RED); + ally4 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap(); + } + + @Test + @DisplayName("마는 기물을 뛰어넘을 수 없다.") + void test1() { + positionPieceMap.put(Position.valueOf(6, 4), horse); + positionPieceMap.put(Position.valueOf(6, 3), ally1); + positionPieceMap.put(Position.valueOf(5, 4), enemy1); + positionPieceMap.put(Position.valueOf(7, 4), ally2); + positionPieceMap.put(Position.valueOf(6, 5), ally3); + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("마는 직선 한 칸, 대각선 한 칸을 가서 기물을 잡을 수 있다.") + void test2() { + positionPieceMap.put(Position.valueOf(6, 4), horse); + positionPieceMap.put(Position.valueOf(5, 6), enemy1); + positionPieceMap.put(Position.valueOf(7, 2), enemy2); + List expected = List.of(Position.valueOf(4, 3), Position.valueOf(4, 5), + Position.valueOf(5, 6), Position.valueOf(7, 6), + Position.valueOf(8, 3), Position.valueOf(8, 5), Position.valueOf(7, 2), + Position.valueOf(5, 2)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("마는 장기판 밖으로 이동할 수 없다.") + void test3() { + positionPieceMap.put(Position.valueOf(1, 1), horse); + positionPieceMap.put(Position.valueOf(1, 2), ally1); + positionPieceMap.put(Position.valueOf(2, 1), ally3); + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = horse.calculateMovablePositions(Position.valueOf(1, 1), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} From 7ffe52ec07392f58211438f98a3944a28c6a9e87 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 18:04:37 +0900 Subject: [PATCH 048/128] =?UTF-8?q?feat(horse):=20=EB=A7=88=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Horse.java | 41 +++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 1bf901b655..3524e5d7bd 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -3,16 +3,52 @@ import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Movement; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleWithNoTraces; import janggi.domain.team.TeamType; import java.util.List; public class Horse implements Piece { private static final PieceType PIECE_TYPE = PieceType.HORSE; + private static final PieceAction PIECE_ACTION; private static final List UNCATCHABLE_PIECE_TYPES = List.of(); private final TeamType teamType; + static { + final List rules = List.of( + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, 1)), + new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, 1)), + new Movement(1, Direction.valueOf(1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(-1, 0)), + new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(-1, 0)), + new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, -1)), + new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, -1)), + new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(1, 0)), + new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(1, 0)), + new Movement(1, Direction.valueOf(1, 1))) + )); + + PIECE_ACTION = new PieceAction(rules); + } + public Horse(final TeamType teamType) { this.teamType = teamType; } @@ -34,11 +70,12 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return List.of(); + return PIECE_ACTION.calculateMovablePositions(from,boardMediator); } @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( + teamType); } } From e86d1431f413d4ba95a4e67b79901fb93575f935 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 18:20:07 +0900 Subject: [PATCH 049/128] =?UTF-8?q?test(general):=20=EC=9E=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=ED=85=8C?= =?UTF-8?q?=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/janggi/domain/GeneralTest.java | 110 +++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/test/java/janggi/domain/GeneralTest.java diff --git a/src/test/java/janggi/domain/GeneralTest.java b/src/test/java/janggi/domain/GeneralTest.java new file mode 100644 index 0000000000..d24f9818e5 --- /dev/null +++ b/src/test/java/janggi/domain/GeneralTest.java @@ -0,0 +1,110 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.General; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class GeneralTest { + + @Nested + @DisplayName("이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece general; + static Piece enemy1; + static Piece enemy2; + static Piece enemy3; + static Piece enemy4; + static Piece ally1; + static Piece ally2; + static Piece ally3; + static Piece ally4; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + general = new General(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy3 = new Soldier(TeamType.BLUE); + enemy4 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + ally3 = new Soldier(TeamType.RED); + ally4 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap(); + } + + @Test + @DisplayName("장은 기물을 뛰어넘을 수 없다.") + void test1() { + positionPieceMap.put(Position.valueOf(6, 4), general); + positionPieceMap.put(Position.valueOf(5, 3), ally1); + positionPieceMap.put(Position.valueOf(5, 4), ally2); + positionPieceMap.put(Position.valueOf(5, 5), ally3); + positionPieceMap.put(Position.valueOf(6, 3), ally4); + positionPieceMap.put(Position.valueOf(6, 5), enemy1); + positionPieceMap.put(Position.valueOf(7, 3), enemy2); + positionPieceMap.put(Position.valueOf(7, 4), enemy3); + positionPieceMap.put(Position.valueOf(7, 5), enemy4); + + List expected = List.of(Position.valueOf(6, 5), Position.valueOf(7, 3), + Position.valueOf(7, 4), Position.valueOf(7, 5)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = general.calculateMovablePositions(Position.valueOf(6, 4), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("장은 모든 방향 중 한 칸을 가서 기물을 잡을 수 있다.") + void test2() { + positionPieceMap.put(Position.valueOf(6, 4), general); + positionPieceMap.put(Position.valueOf(6, 5), enemy1); + positionPieceMap.put(Position.valueOf(7, 3), enemy2); + List expected = List.of(Position.valueOf(5, 3), Position.valueOf(5, 4), + Position.valueOf(5, 5), Position.valueOf(6, 3), Position.valueOf(6, 5), Position.valueOf(7, 3), + Position.valueOf(7, 4), Position.valueOf(7, 5)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = general.calculateMovablePositions(Position.valueOf(6, 4), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("장은 장기판 밖으로 이동할 수 없다.") + void test3() { + positionPieceMap.put(Position.valueOf(1, 1), general); + positionPieceMap.put(Position.valueOf(1, 2), ally1); + positionPieceMap.put(Position.valueOf(2, 1), ally2); + positionPieceMap.put(Position.valueOf(2, 2), ally3); + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = general.calculateMovablePositions(Position.valueOf(1, 1), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} From 6296e875fd4b904135e43ad4dbbdcaf97e3f15b6 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 18:20:27 +0900 Subject: [PATCH 050/128] =?UTF-8?q?feat(general):=20=EC=9E=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=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/janggi/domain/piece/General.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 39c4b3e755..f56fd0cc83 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -3,14 +3,32 @@ import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Movement; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleWithTraces; import janggi.domain.team.TeamType; import java.util.List; public class General implements Piece { private static final PieceType PIECE_TYPE = PieceType.GENERAL; + private static final PieceAction PIECE_ACTION; private static final List UNCATCHABLE_PIECE_TYPES = List.of(); + static { + final List rules = List.of( + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 0)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 0)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 1))))); + PIECE_ACTION = new PieceAction(rules); + } + private final TeamType teamType; public General(final TeamType teamType) { @@ -34,7 +52,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return List.of(); + return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } @Override From d8788eae070faf1259a314d5e99918fb51d4a988 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 18:25:47 +0900 Subject: [PATCH 051/128] =?UTF-8?q?test(guard):=20=EC=82=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=ED=85=8C?= =?UTF-8?q?=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/janggi/domain/GuardTest.java | 110 +++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/test/java/janggi/domain/GuardTest.java diff --git a/src/test/java/janggi/domain/GuardTest.java b/src/test/java/janggi/domain/GuardTest.java new file mode 100644 index 0000000000..a38e44df66 --- /dev/null +++ b/src/test/java/janggi/domain/GuardTest.java @@ -0,0 +1,110 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Guard; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class GuardTest { + + @Nested + @DisplayName("이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece guard; + static Piece enemy1; + static Piece enemy2; + static Piece enemy3; + static Piece enemy4; + static Piece ally1; + static Piece ally2; + static Piece ally3; + static Piece ally4; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + guard = new Guard(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy3 = new Soldier(TeamType.BLUE); + enemy4 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + ally3 = new Soldier(TeamType.RED); + ally4 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap(); + } + + @Test + @DisplayName("사는 기물을 뛰어넘을 수 없다.") + void test1() { + positionPieceMap.put(Position.valueOf(6, 4), guard); + positionPieceMap.put(Position.valueOf(5, 3), ally1); + positionPieceMap.put(Position.valueOf(5, 4), ally2); + positionPieceMap.put(Position.valueOf(5, 5), ally3); + positionPieceMap.put(Position.valueOf(6, 3), ally4); + positionPieceMap.put(Position.valueOf(6, 5), enemy1); + positionPieceMap.put(Position.valueOf(7, 3), enemy2); + positionPieceMap.put(Position.valueOf(7, 4), enemy3); + positionPieceMap.put(Position.valueOf(7, 5), enemy4); + + List expected = List.of(Position.valueOf(6, 5), Position.valueOf(7, 3), + Position.valueOf(7, 4), Position.valueOf(7, 5)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("사는 모든 방향 중 한 칸을 가서 기물을 잡을 수 있다.") + void test2() { + positionPieceMap.put(Position.valueOf(6, 4), guard); + positionPieceMap.put(Position.valueOf(6, 5), enemy1); + positionPieceMap.put(Position.valueOf(7, 3), enemy2); + List expected = List.of(Position.valueOf(5, 3), Position.valueOf(5, 4), + Position.valueOf(5, 5), Position.valueOf(6, 3), Position.valueOf(6, 5), Position.valueOf(7, 3), + Position.valueOf(7, 4), Position.valueOf(7, 5)); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("사는 장기판 밖으로 이동할 수 없다.") + void test3() { + positionPieceMap.put(Position.valueOf(1, 1), guard); + positionPieceMap.put(Position.valueOf(1, 2), ally1); + positionPieceMap.put(Position.valueOf(2, 1), ally2); + positionPieceMap.put(Position.valueOf(2, 2), ally3); + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + List actual = guard.calculateMovablePositions(Position.valueOf(1, 1), + boardMediator); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} From cb7363edd951435ed7109886cd3ab3c8621b0791 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 18:27:31 +0900 Subject: [PATCH 052/128] =?UTF-8?q?feat(guard):=20=EC=82=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Guard.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 35c37ab972..0c3e30534f 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -3,14 +3,31 @@ import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Movement; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleWithTraces; import janggi.domain.team.TeamType; import java.util.List; public class Guard implements Piece { private static final PieceType PIECE_TYPE = PieceType.GUARD; + private static final PieceAction PIECE_ACTION; private static final List UNCATCHABLE_PIECE_TYPES = List.of(); + static { + final List rules = List.of( + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 0)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 0)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 1))))); + PIECE_ACTION = new PieceAction(rules); + } private final TeamType teamType; public Guard(final TeamType teamType) { @@ -34,7 +51,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return List.of(); + return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } @Override From e785c2fec67f2c8ac21cf5196bb3e32f93ddebc3 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 18:39:12 +0900 Subject: [PATCH 053/128] =?UTF-8?q?test(soldier):=20=EB=B3=91(=EC=A1=B8)?= =?UTF-8?q?=20=EA=B8=B0=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99?= =?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 --- .../java/janggi/domain/BlueSoldierTest.java | 104 ++++++++++++++++++ .../java/janggi/domain/RedSoldierTest.java | 104 ++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 src/test/java/janggi/domain/BlueSoldierTest.java create mode 100644 src/test/java/janggi/domain/RedSoldierTest.java diff --git a/src/test/java/janggi/domain/BlueSoldierTest.java b/src/test/java/janggi/domain/BlueSoldierTest.java new file mode 100644 index 0000000000..73b1a06042 --- /dev/null +++ b/src/test/java/janggi/domain/BlueSoldierTest.java @@ -0,0 +1,104 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class BlueSoldierTest { + + @Nested + @DisplayName("Blue Soldier 이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece blueSoldier; + static Piece enemy1; + static Piece enemy2; + static Piece ally1; + static Piece ally2; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + blueSoldier = new Soldier(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap<>(); + } + + @Test + @DisplayName("청졸은 앞, 좌, 우로 이동할 수 있고 적이 있으면 잡을 수 있다.") + void test1() { + positionPieceMap.put(Position.valueOf(6, 4), blueSoldier); + positionPieceMap.put(Position.valueOf(5, 4), enemy1); + positionPieceMap.put(Position.valueOf(6, 3), enemy2); + + List expected = List.of( + Position.valueOf(5, 4), + Position.valueOf(6, 3), + Position.valueOf(6, 5) + ); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + + List actual = blueSoldier.calculateMovablePositions( + Position.valueOf(6, 4), boardMediator + ); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("청졸은 아군이 있는 위치로 이동할 수 없다.") + void test2() { + positionPieceMap.put(Position.valueOf(6, 4), blueSoldier); + positionPieceMap.put(Position.valueOf(5, 4), ally1); + positionPieceMap.put(Position.valueOf(6, 5), ally2); + + List expected = List.of( + Position.valueOf(6, 3) + ); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + + List actual = blueSoldier.calculateMovablePositions( + Position.valueOf(6, 4), boardMediator + ); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("청졸은 장기판 밖으로 이동할 수 없다.") + void test3() { + positionPieceMap.put(Position.valueOf(1, 1), blueSoldier); + positionPieceMap.put(Position.valueOf(1, 2), ally1); + + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + + List actual = blueSoldier.calculateMovablePositions( + Position.valueOf(1, 1), boardMediator + ); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} \ No newline at end of file diff --git a/src/test/java/janggi/domain/RedSoldierTest.java b/src/test/java/janggi/domain/RedSoldierTest.java new file mode 100644 index 0000000000..074f8e6949 --- /dev/null +++ b/src/test/java/janggi/domain/RedSoldierTest.java @@ -0,0 +1,104 @@ +package janggi.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardMediator; +import janggi.domain.board.BoardMediatorImpl; +import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; +import janggi.domain.team.TeamType; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class RedSoldierTest { + + @Nested + @DisplayName("Red Soldier 이동 가능한 위치 계산 테스트") + class CalculateMovablePositions { + + static Piece redSoldier; + static Piece enemy1; + static Piece enemy2; + static Piece ally1; + static Piece ally2; + static Map positionPieceMap; + + @BeforeEach + void setUp() { + redSoldier = new Soldier(TeamType.RED); + enemy1 = new Soldier(TeamType.BLUE); + enemy2 = new Soldier(TeamType.BLUE); + ally1 = new Soldier(TeamType.RED); + ally2 = new Soldier(TeamType.RED); + positionPieceMap = new LinkedHashMap<>(); + } + + @Test + @DisplayName("홍졸은 앞, 좌, 우로 이동할 수 있고 적이 있으면 잡을 수 있다.") + void test1() { + positionPieceMap.put(Position.valueOf(6, 4), redSoldier); + positionPieceMap.put(Position.valueOf(7, 4), enemy1); + positionPieceMap.put(Position.valueOf(6, 3), enemy2); + + List expected = List.of( + Position.valueOf(7, 4), + Position.valueOf(6, 3), + Position.valueOf(6, 5) + ); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + + List actual = redSoldier.calculateMovablePositions( + Position.valueOf(6, 4), boardMediator + ); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("홍졸은 아군이 있는 위치로 이동할 수 없다.") + void test2() { + positionPieceMap.put(Position.valueOf(6, 4), redSoldier); + positionPieceMap.put(Position.valueOf(7, 4), ally1); + positionPieceMap.put(Position.valueOf(6, 5), ally2); + + List expected = List.of( + Position.valueOf(6, 3) + ); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + + List actual = redSoldier.calculateMovablePositions( + Position.valueOf(6, 4), boardMediator + ); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("홍졸은 장기판 밖으로 이동할 수 없다.") + void test3() { + positionPieceMap.put(Position.valueOf(10, 1), redSoldier); + positionPieceMap.put(Position.valueOf(10, 2), ally1); + + List expected = List.of(); + + Board board = new Board(positionPieceMap); + BoardMediator boardMediator = new BoardMediatorImpl(board); + + List actual = redSoldier.calculateMovablePositions( + Position.valueOf(10, 1), boardMediator + ); + + assertThat(actual).hasSameElementsAs(expected); + } + } +} \ No newline at end of file From 83b42af9a7ba9a59b8e1313332ee33ef72d53235 Mon Sep 17 00:00:00 2001 From: EveryPine Date: Fri, 27 Mar 2026 18:45:21 +0900 Subject: [PATCH 054/128] =?UTF-8?q?feat(soldier):=20=EB=B3=91(=EC=A1=B8)?= =?UTF-8?q?=20=EA=B8=B0=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/piece/Soldier.java | 28 +++++++++++++++++-- .../java/janggi/domain/BlueSoldierTest.java | 10 +++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 42ee2b64e7..eef897c257 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -3,13 +3,33 @@ import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.Direction; +import janggi.domain.movement.Movement; +import janggi.domain.movement.Rule; +import janggi.domain.movement.RuleWithTraces; import janggi.domain.team.TeamType; import java.util.List; public class Soldier implements Piece { private static final PieceType PIECE_TYPE = PieceType.SOLDIER; + private static final PieceAction RED_PIECE_ACTION; + private static final PieceAction BLUE_PIECE_ACTION; private static final List UNCATCHABLE_PIECE_TYPES = List.of(); + + static { + final List redRules = List.of( + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 0))))); + final List blueRules = List.of( + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), + new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 0))))); + RED_PIECE_ACTION = new PieceAction(redRules); + BLUE_PIECE_ACTION = new PieceAction(blueRules); + } + private final TeamType teamType; public Soldier(final TeamType teamType) { @@ -33,11 +53,15 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return List.of(); + if (teamType == TeamType.RED) { + return RED_PIECE_ACTION.calculateMovablePositions(from, boardMediator); + } + return BLUE_PIECE_ACTION.calculateMovablePositions(from, boardMediator); } @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); + return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( + teamType); } } diff --git a/src/test/java/janggi/domain/BlueSoldierTest.java b/src/test/java/janggi/domain/BlueSoldierTest.java index 73b1a06042..bca4796a80 100644 --- a/src/test/java/janggi/domain/BlueSoldierTest.java +++ b/src/test/java/janggi/domain/BlueSoldierTest.java @@ -31,11 +31,11 @@ class CalculateMovablePositions { @BeforeEach void setUp() { - blueSoldier = new Soldier(TeamType.RED); - enemy1 = new Soldier(TeamType.BLUE); - enemy2 = new Soldier(TeamType.BLUE); - ally1 = new Soldier(TeamType.RED); - ally2 = new Soldier(TeamType.RED); + blueSoldier = new Soldier(TeamType.BLUE); + enemy1 = new Soldier(TeamType.RED); + enemy2 = new Soldier(TeamType.RED); + ally1 = new Soldier(TeamType.BLUE); + ally2 = new Soldier(TeamType.BLUE); positionPieceMap = new LinkedHashMap<>(); } From 0fc7c041bdc26ca3fa0119a6ddcd659fbb1f2693 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 19:31:40 +0900 Subject: [PATCH 055/128] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=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/janggi/domain/board/Board.java | 13 ---------- .../janggi/domain/board/BoardGenerator.java | 4 +-- .../janggi/domain/board/BoardMediator.java | 2 +- .../java/janggi/domain/team/BlueTeam.java | 5 ---- src/main/java/janggi/domain/team/RedTeam.java | 7 ------ src/main/java/janggi/domain/team/Team.java | 2 -- src/main/java/janggi/global/Pair.java | 6 ----- src/main/java/janggi/utils/Lists.java | 25 ------------------- 8 files changed, 2 insertions(+), 62 deletions(-) delete mode 100644 src/main/java/janggi/global/Pair.java delete mode 100644 src/main/java/janggi/utils/Lists.java diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 1571a377dc..d10ec872a6 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -2,8 +2,6 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; public class Board { @@ -28,15 +26,4 @@ public Piece findPieceByPosition(final Position position) { } return positionPieceMap.get(position); } - - public Map offerSelectedPieceMap(final List positions) { - final Map selected = new LinkedHashMap<>(); - positions.forEach(position -> { - if (!isBlank(position)) { - selected.put(position, findPieceByPosition(position)); - } - }); - - return selected; - } } diff --git a/src/main/java/janggi/domain/board/BoardGenerator.java b/src/main/java/janggi/domain/board/BoardGenerator.java index 1f7e312e0d..1440bc4b86 100644 --- a/src/main/java/janggi/domain/board/BoardGenerator.java +++ b/src/main/java/janggi/domain/board/BoardGenerator.java @@ -1,22 +1,20 @@ package janggi.domain.board; import janggi.domain.Position; -import janggi.domain.team.Team; import janggi.domain.piece.Piece; +import janggi.domain.team.Team; import java.util.LinkedHashMap; import java.util.Map; public final class BoardGenerator { private BoardGenerator() { - } public static Board generate(final Team redTeam, final Team blueTeam) { final Map positionPieceMap = new LinkedHashMap<>(); positionPieceMap.putAll(redTeam.generatePieces()); positionPieceMap.putAll(blueTeam.generatePieces()); - return new Board(positionPieceMap); } } diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java index cd43072992..865c8bfcbb 100644 --- a/src/main/java/janggi/domain/board/BoardMediator.java +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -5,6 +5,6 @@ public interface BoardMediator { boolean existsInPosition(Position position); - Piece getPieceInPosition(Position position); + Piece getPieceInPosition(Position position); } diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java index 87735ec45f..81920d5b45 100644 --- a/src/main/java/janggi/domain/team/BlueTeam.java +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -30,9 +30,4 @@ public Map generatePieces() { public String getName() { return TEAM_TYPE.getName(); } - - @Override - public boolean hasPiece(final Piece piece) { - return piece.belongsToTeam(TEAM_TYPE); - } } diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java index 537b0dcb6f..dbfdaea391 100644 --- a/src/main/java/janggi/domain/team/RedTeam.java +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -31,11 +31,4 @@ public Map generatePieces() { public String getName() { return TEAM_TYPE.getName(); } - - @Override - public boolean hasPiece(final Piece piece) { - return piece.belongsToTeam(TEAM_TYPE); - } - - } diff --git a/src/main/java/janggi/domain/team/Team.java b/src/main/java/janggi/domain/team/Team.java index f44a0c3da1..d8bda186ed 100644 --- a/src/main/java/janggi/domain/team/Team.java +++ b/src/main/java/janggi/domain/team/Team.java @@ -8,6 +8,4 @@ public interface Team { Map generatePieces(); String getName(); - - boolean hasPiece(Piece piece); } diff --git a/src/main/java/janggi/global/Pair.java b/src/main/java/janggi/global/Pair.java deleted file mode 100644 index 715f406b68..0000000000 --- a/src/main/java/janggi/global/Pair.java +++ /dev/null @@ -1,6 +0,0 @@ -package janggi.global; - -public record Pair(T left, U right) { - -} - diff --git a/src/main/java/janggi/utils/Lists.java b/src/main/java/janggi/utils/Lists.java deleted file mode 100644 index 91fd907b42..0000000000 --- a/src/main/java/janggi/utils/Lists.java +++ /dev/null @@ -1,25 +0,0 @@ -package janggi.utils; - -import janggi.global.Pair; -import java.util.List; -import java.util.stream.Stream; - -public final class Lists { - - private Lists() { - - } - - public static List> cartesianProduct(final List list1, - final List list2) { - return list1.stream() - .flatMap(t -> pairWithAll(t, list2)) - .toList(); - } - - private static Stream> pairWithAll(final T t, final List list) { - return list.stream() - .map(u -> new Pair<>(t, u)); - } - -} From 7dc30dc646c81bb3b5198ffc8977e4ea76415990 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 23:13:19 +0900 Subject: [PATCH 056/128] =?UTF-8?q?refactor:=20Movement=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B0=80=EB=8F=85=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주석 추가하였습니다. --- .../java/janggi/domain/movement/Movement.java | 83 +++++++++++-------- .../janggi/domain/movement/RuleOfCannon.java | 10 +-- .../domain/movement/RuleWithNoTraces.java | 4 +- .../janggi/domain/movement/MovementTest.java | 34 ++++---- 4 files changed, 74 insertions(+), 57 deletions(-) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 3d87828613..4a023ea072 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -20,13 +20,15 @@ public boolean canMove(final Position from) { return from.checkNextBound(maxDistance, direction); } - public boolean canKill(final Piece me, final Position from, final BoardMediator boardMediator) { + // 마지막 movement에서만 사용 + // 현재 기물이 다음으로 가는 곳에서 갈 수 있는 칸이 있는지 + public boolean hasReachablePosition(final Piece me, final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (!boardMediator.existsInPosition(to)) { + final Position to = calculateNextPosition(from, distance); + if (!hasPieceAt(to, boardMediator)) { return true; } - Piece target = boardMediator.getPieceInPosition(to); + final Piece target = findPieceAt(to, boardMediator); if (me.canKill(target)) { return true; } @@ -34,58 +36,73 @@ public boolean canKill(final Piece me, final Position from, final BoardMediator return false; } + // 이동 경로 중 막히는지 public boolean isBlocked(final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { + final Position to = calculateNextPosition(from, distance); + if (hasPieceAt(to, boardMediator)) { return true; } } return false; } - public Position calculateDestination(final Position from, final Piece piece, - final BoardMediator boardMediator) { + // 처음 만나는 기물 찾기(그 기물이 적군이라면 기물의 위치 반환, 아군이라면 이전 위치 반환) + public Position calculateDestination(final Position from, final Piece piece, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { - Piece toPiece = boardMediator.getPieceInPosition(to); - if (toPiece.belongsToTeam(piece.getTeamType())) { - return from.calculateNext(distance - 1, direction); - } - return from.calculateNext(distance, direction); + final Position to = calculateNextPosition(from, distance); + if (!hasPieceAt(to, boardMediator)) { + continue; } + final Piece target = findPieceAt(to, boardMediator); + if (target.belongsToTeam(piece.getTeamType())) { + return calculateNextPosition(from, distance - 1); + } + return to; } - return from.calculateNext(maxDistance, direction); + return calculateNextPosition(from, maxDistance); } - public Position calculateBlockedPosition(final Position from, final Piece piece, - final BoardMediator boardMediator) { + // 처음 만나는 기물 위치 반환, 만약 끝까지 가도 없으면 그 끝 위치 반환 + public Position findFirstOccupiedPositionOrMax(final Position from, final Piece piece, + final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { - return from.calculateNext(distance, direction); + final Position to = calculateNextPosition(from, distance); + if (hasPieceAt(to, boardMediator)) { + return to; } } - return from.calculateNext(maxDistance, direction); + return calculateNextPosition(from, maxDistance); } // 이동 가능한 경로의 자취 위치 리스트를 반환한다. - public List calculateTraces(final Position from, final Piece piece, - final BoardMediator boardMediator) { + // 경로에 장애물을 만나면 그때까지의 리스트를 반환하고, 적을 만난다면 적의 좌표를 포함하여 반환한다. + public List calculateTraces(final Position from, final Piece piece, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); for (int distance = 1; distance <= maxDistance; distance++) { - Position to = from.calculateNext(distance, direction); - if (boardMediator.existsInPosition(to)) { - Piece toPiece = boardMediator.getPieceInPosition(to); - if (!toPiece.belongsToTeam(piece.getTeamType()) && piece.canKill( - toPiece)) { - traces.add(to); - } - return traces; + Position to = calculateNextPosition(from, distance); + if (!hasPieceAt(to, boardMediator)) { + traces.add(to); + continue; + } + final Piece target = findPieceAt(to, boardMediator); + if (!target.belongsToTeam(piece.getTeamType()) && piece.canKill(target)) { + traces.add(to); } - traces.add(to); + return traces; } return traces; } + + private Position calculateNextPosition(final Position from, final int distance) { + return from.calculateNext(distance, direction); + } + + private boolean hasPieceAt(final Position position, final BoardMediator boardMediator) { + return boardMediator.existsInPosition(position); + } + + private Piece findPieceAt(final Position position, final BoardMediator boardMediator) { + return boardMediator.getPieceInPosition(position); + } } diff --git a/src/main/java/janggi/domain/movement/RuleOfCannon.java b/src/main/java/janggi/domain/movement/RuleOfCannon.java index 6f23ab776d..b599a51ad4 100644 --- a/src/main/java/janggi/domain/movement/RuleOfCannon.java +++ b/src/main/java/janggi/domain/movement/RuleOfCannon.java @@ -19,8 +19,8 @@ public RuleOfCannon(final Direction direction) { private List generateMovementOrder(final Direction direction) { return List.of( - new Movement(MAXIMUM_ROW, direction), - new Movement(MAXIMUM_ROW, direction)); + new Movement(MAXIMUM_ROW, direction), + new Movement(MAXIMUM_ROW, direction)); } @Override @@ -30,16 +30,16 @@ public List execute(Position from, final BoardMediator boardMediator) final Piece piece = boardMediator.getPieceInPosition(from); // 포다리로 이동 - from = firstMovement.calculateBlockedPosition(from, piece, boardMediator); + from = firstMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); // 포다리로 판정된 위치에 실제로는 기물이 없거나 위치에 포가 존재하는 경우 이동 불가능 if (!boardMediator.existsInPosition(from) - || boardMediator.getPieceInPosition(from).getPieceType() == PieceType.CANNON) { + || boardMediator.getPieceInPosition(from).getPieceType() == PieceType.CANNON) { return List.of(); } final List traces = new ArrayList<>( - secondMovement.calculateTraces(from, piece, boardMediator)); + secondMovement.calculateTraces(from, piece, boardMediator)); return traces; } } diff --git a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java index 73467f4f16..93b4492352 100644 --- a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java @@ -25,8 +25,8 @@ public List execute(Position from, final BoardMediator boardMediator) } from = movement.calculateDestination(from, piece, boardMediator); } - if (lastMovement.canMove(from) && lastMovement.canKill(piece, from, boardMediator)) { - from = lastMovement.calculateBlockedPosition(from, piece, boardMediator); + if (lastMovement.canMove(from) && lastMovement.hasReachablePosition(piece, from, boardMediator)) { + from = lastMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); return List.of(from); } return List.of(); diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index e6e7ecfd47..373ec1a028 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -46,7 +46,7 @@ void success_1() { Movement Movement = new Movement(1, direction); boolean expected = true; - boolean actual = Movement.canKill(me, from, boardMediator); + boolean actual = Movement.hasReachablePosition(me, from, boardMediator); assertThat(actual).isEqualTo(expected); } @@ -61,7 +61,7 @@ void success_2() { Movement Movement = new Movement(1, direction); boolean expected = false; - boolean actual = Movement.canKill(me, from, boardMediator); + boolean actual = Movement.hasReachablePosition(me, from, boardMediator); assertThat(actual).isEqualTo(expected); } @@ -75,7 +75,7 @@ void success_3() { Movement Movement = new Movement(1, direction); boolean expected = true; - boolean actual = Movement.canKill(me, from, boardMediator); + boolean actual = Movement.hasReachablePosition(me, from, boardMediator); assertThat(actual).isEqualTo(expected); } @@ -151,8 +151,8 @@ void success_1() { Position expected = Position.valueOf(5, 5); Position actual = Movement.calculateDestination(from, - boardMediator.getPieceInPosition(from), - boardMediator); + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -169,8 +169,8 @@ void success_2() { Position expected = Position.valueOf(5, 6); Position actual = Movement.calculateDestination(from, - boardMediator.getPieceInPosition(from), - boardMediator); + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -186,8 +186,8 @@ void success_3() { Position expected = Position.valueOf(5, 7); Position actual = Movement.calculateDestination(from, - boardMediator.getPieceInPosition(from), - boardMediator); + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).isEqualTo(expected); } @@ -218,8 +218,8 @@ void success_1() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); List actual = Movement.calculateTraces(from, - boardMediator.getPieceInPosition(from), - boardMediator); + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -234,11 +234,11 @@ void success_2() { Direction direction = Direction.valueOf(0, 1); Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), - Position.valueOf(5, 6)); + Position.valueOf(5, 6)); List actual = Movement.calculateTraces(from, - boardMediator.getPieceInPosition(from), - boardMediator); + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -252,11 +252,11 @@ void success_3() { Direction direction = Direction.valueOf(0, 1); Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), - Position.valueOf(5, 6), Position.valueOf(5, 7)); + Position.valueOf(5, 6), Position.valueOf(5, 7)); List actual = Movement.calculateTraces(from, - boardMediator.getPieceInPosition(from), - boardMediator); + boardMediator.getPieceInPosition(from), + boardMediator); assertThat(actual).hasSameElementsAs(expected); } From bfc634ab12f605d6dfe5a7f61c7eff930f022999 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 23:16:32 +0900 Subject: [PATCH 057/128] =?UTF-8?q?refactor:=20=EC=83=9D=EC=84=B1=EC=9E=90?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9D=BC=EA=B8=89=20=EC=BB=AC=EB=A0=89?= =?UTF-8?q?=EC=85=98=20=EB=B0=A9=EC=96=B4=EC=A0=81=20=EB=B3=B5=EC=82=AC=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/janggi/domain/piece/PieceAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/piece/PieceAction.java b/src/main/java/janggi/domain/piece/PieceAction.java index d9dfde8e3a..e0c3edd6dd 100644 --- a/src/main/java/janggi/domain/piece/PieceAction.java +++ b/src/main/java/janggi/domain/piece/PieceAction.java @@ -10,7 +10,7 @@ public class PieceAction { private final List rules; public PieceAction(List rules) { - this.rules = rules; + this.rules = List.copyOf(rules); } public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { From 30cca544149d0bd83633e6570390741919bf536b Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 23:33:20 +0900 Subject: [PATCH 058/128] =?UTF-8?q?refactor:=20RuleWithNoTraces=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/RuleWithNoTraces.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java index 93b4492352..fd98d9b564 100644 --- a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithNoTraces.java @@ -3,7 +3,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; -import java.util.ArrayList; import java.util.List; public class RuleWithNoTraces implements Rule { @@ -17,24 +16,22 @@ public RuleWithNoTraces(final List movementOrder) { @Override public List execute(Position from, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); - final List movementOrderWithoutLast = getMovementOrderWithoutLast(); - final Movement lastMovement = movementOrder.getLast(); - for (final Movement movement : movementOrderWithoutLast) { + for (int index = 0; index < movementOrder.size() - 1; index++) { + final Movement movement = movementOrder.get(index); if (!movement.canMove(from) || movement.isBlocked(from, boardMediator)) { return List.of(); } from = movement.calculateDestination(from, piece, boardMediator); } - if (lastMovement.canMove(from) && lastMovement.hasReachablePosition(piece, from, boardMediator)) { - from = lastMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); - return List.of(from); - } - return List.of(); + return findLastPosition(from, piece, boardMediator); } - private List getMovementOrderWithoutLast() { - final List movementOrderWithoutLast = new ArrayList<>(movementOrder); - movementOrderWithoutLast.removeLast(); - return movementOrderWithoutLast; + private List findLastPosition(final Position from, final Piece piece, final BoardMediator boardMediator) { + final Movement lastMovement = movementOrder.getLast(); + if (!lastMovement.canMove(from) || !lastMovement.hasReachablePosition(piece, from, boardMediator)) { + return List.of(); + } + final Position destination = lastMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); + return List.of(destination); } } From bab1236cff5818407510cf0f3cdc46056c8ab214 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 23:39:33 +0900 Subject: [PATCH 059/128] =?UTF-8?q?refactor:=20RuleWithTraces=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/RuleWithTraces.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/janggi/domain/movement/RuleWithTraces.java b/src/main/java/janggi/domain/movement/RuleWithTraces.java index 5a2b1e9347..fac0610de8 100644 --- a/src/main/java/janggi/domain/movement/RuleWithTraces.java +++ b/src/main/java/janggi/domain/movement/RuleWithTraces.java @@ -17,21 +17,21 @@ public RuleWithTraces(final List movementOrder) { @Override public List execute(Position from, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); - final List movementOrderWithoutLast = getMovementOrderWithoutLast(); - final Movement lastMovement = movementOrder.getLast(); final Piece piece = boardMediator.getPieceInPosition(from); - for (final Movement movement : movementOrderWithoutLast) { + for (int index = 0; index < movementOrder.size() - 1; index++) { + final Movement movement = movementOrder.get(index); traces.addAll(movement.calculateTraces(from, piece, boardMediator)); - traces.add(movement.calculateDestination(from, piece, boardMediator)); - from = traces.getLast(); + final Position destination = movement.calculateDestination(from, piece, boardMediator); + traces.add(destination); + from = destination; } - traces.addAll(lastMovement.calculateTraces(from, piece, boardMediator)); - return traces; + return findLastPosition(from, piece, boardMediator, traces); } - private List getMovementOrderWithoutLast() { - final List movementOrderWithoutLast = new ArrayList<>(movementOrder); - movementOrderWithoutLast.removeLast(); - return movementOrderWithoutLast; + private List findLastPosition(final Position from, final Piece piece, final BoardMediator boardMediator, + final List traces) { + final Movement lastMovement = movementOrder.getLast(); + traces.addAll(lastMovement.calculateTraces(from, piece, boardMediator)); + return traces; } } From 672895a454e98ca261b6e46a38e4c7a7d59c15da Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 23:44:21 +0900 Subject: [PATCH 060/128] =?UTF-8?q?refactor:=20RuleOfCannon=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/movement/RuleOfCannon.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/domain/movement/RuleOfCannon.java b/src/main/java/janggi/domain/movement/RuleOfCannon.java index b599a51ad4..c9909b8172 100644 --- a/src/main/java/janggi/domain/movement/RuleOfCannon.java +++ b/src/main/java/janggi/domain/movement/RuleOfCannon.java @@ -25,21 +25,15 @@ private List generateMovementOrder(final Direction direction) { @Override public List execute(Position from, final BoardMediator boardMediator) { - final Movement firstMovement = movementOrder.getFirst(); - final Movement secondMovement = movementOrder.getLast(); + final Movement findBridgeMovement = movementOrder.getFirst(); + final Movement findTraceesMovement = movementOrder.getLast(); final Piece piece = boardMediator.getPieceInPosition(from); - - // 포다리로 이동 - from = firstMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); - - // 포다리로 판정된 위치에 실제로는 기물이 없거나 위치에 포가 존재하는 경우 이동 불가능 + from = findBridgeMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); if (!boardMediator.existsInPosition(from) || boardMediator.getPieceInPosition(from).getPieceType() == PieceType.CANNON) { return List.of(); } - - final List traces = new ArrayList<>( - secondMovement.calculateTraces(from, piece, boardMediator)); + final List traces = new ArrayList<>(findTraceesMovement.calculateTraces(from, piece, boardMediator)); return traces; } } From 2e4c672a0dd1b46b87007ad18b4a555f2eae711f Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 27 Mar 2026 23:50:08 +0900 Subject: [PATCH 061/128] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - setup 패키지 생성 --- .../janggi/controller/JanggiController.java | 2 +- .../janggi/domain/command/SetupCommand.java | 10 +-- .../janggi/domain/movement/RuleOfCannon.java | 2 +- src/main/java/janggi/domain/piece/Cannon.java | 9 ++- .../java/janggi/domain/piece/Chariot.java | 1 - .../java/janggi/domain/piece/Elephant.java | 71 +++++++++---------- .../java/janggi/domain/piece/General.java | 1 - src/main/java/janggi/domain/piece/Guard.java | 1 - src/main/java/janggi/domain/piece/Horse.java | 1 - src/main/java/janggi/domain/piece/Piece.java | 1 - .../janggi/domain/{ => piece}/PieceType.java | 12 +--- .../java/janggi/domain/piece/Soldier.java | 1 - .../{ => setup}/InnerElephantSetupPolicy.java | 4 +- .../{ => setup}/LeftElephantSetupPolicy.java | 4 +- .../{ => setup}/OuterElephantSetupPolicy.java | 4 +- .../{ => setup}/RightElephantSetupPolicy.java | 4 +- .../domain/{ => setup}/SetupPolicy.java | 4 +- .../java/janggi/domain/team/BlueTeam.java | 4 +- src/main/java/janggi/domain/team/RedTeam.java | 4 +- src/main/java/janggi/dto/BoardDto.java | 40 +++++------ src/main/java/janggi/view/OutputView.java | 4 -- .../janggi/domain/BoardGeneratorTest.java | 1 + src/test/java/janggi/domain/BoardTest.java | 9 ++- src/test/java/janggi/domain/CannonTest.java | 46 ++++++------ src/test/java/janggi/domain/GuardTest.java | 12 ++-- src/test/java/janggi/domain/HorseTest.java | 12 ++-- .../domain/InnerElephantSetupPolicyTest.java | 2 + .../domain/LeftElephantSetupPolicyTest.java | 2 + .../domain/OuterElephantSetupPolicyTest.java | 2 + .../domain/RightElephantSetupPolicyTest.java | 2 + .../domain/movement/RuleOfCannonTest.java | 1 - .../fixture/SetupPolicyTestFixture.java | 2 +- 32 files changed, 136 insertions(+), 139 deletions(-) rename src/main/java/janggi/domain/{ => piece}/PieceType.java (63%) rename src/main/java/janggi/domain/{ => setup}/InnerElephantSetupPolicy.java (85%) rename src/main/java/janggi/domain/{ => setup}/LeftElephantSetupPolicy.java (85%) rename src/main/java/janggi/domain/{ => setup}/OuterElephantSetupPolicy.java (85%) rename src/main/java/janggi/domain/{ => setup}/RightElephantSetupPolicy.java (85%) rename src/main/java/janggi/domain/{ => setup}/SetupPolicy.java (92%) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 943a15c034..028812ea48 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -1,9 +1,9 @@ package janggi.controller; -import janggi.domain.SetupPolicy; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; import janggi.domain.command.SetupCommand; +import janggi.domain.setup.SetupPolicy; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import janggi.domain.team.Team; diff --git a/src/main/java/janggi/domain/command/SetupCommand.java b/src/main/java/janggi/domain/command/SetupCommand.java index 600d7607d7..c6be565a1d 100644 --- a/src/main/java/janggi/domain/command/SetupCommand.java +++ b/src/main/java/janggi/domain/command/SetupCommand.java @@ -1,10 +1,10 @@ package janggi.domain.command; -import janggi.domain.InnerElephantSetupPolicy; -import janggi.domain.LeftElephantSetupPolicy; -import janggi.domain.OuterElephantSetupPolicy; -import janggi.domain.RightElephantSetupPolicy; -import janggi.domain.SetupPolicy; +import janggi.domain.setup.InnerElephantSetupPolicy; +import janggi.domain.setup.LeftElephantSetupPolicy; +import janggi.domain.setup.OuterElephantSetupPolicy; +import janggi.domain.setup.RightElephantSetupPolicy; +import janggi.domain.setup.SetupPolicy; import java.util.Arrays; import java.util.function.Supplier; diff --git a/src/main/java/janggi/domain/movement/RuleOfCannon.java b/src/main/java/janggi/domain/movement/RuleOfCannon.java index c9909b8172..1fe24073c7 100644 --- a/src/main/java/janggi/domain/movement/RuleOfCannon.java +++ b/src/main/java/janggi/domain/movement/RuleOfCannon.java @@ -2,10 +2,10 @@ import static janggi.domain.Position.MAXIMUM_ROW; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index e681845864..69bf5896cf 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; @@ -17,10 +16,10 @@ public class Cannon implements Piece { static { final List rules = List.of( - new RuleOfCannon(Direction.valueOf(1, 0)), - new RuleOfCannon(Direction.valueOf(-1, 0)), - new RuleOfCannon(Direction.valueOf(0, 1)), - new RuleOfCannon(Direction.valueOf(0, -1))); + new RuleOfCannon(Direction.valueOf(1, 0)), + new RuleOfCannon(Direction.valueOf(-1, 0)), + new RuleOfCannon(Direction.valueOf(0, 1)), + new RuleOfCannon(Direction.valueOf(0, -1))); PIECE_ACTION = new PieceAction(rules); } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index de12330912..b8c66739ab 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -3,7 +3,6 @@ import static janggi.domain.Position.MAXIMUM_COLUMN; import static janggi.domain.Position.MAXIMUM_ROW; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 245c3639a1..ae45fcac90 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; @@ -18,39 +17,39 @@ public class Elephant implements Piece { static { final List rules = List.of( - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(1, Direction.valueOf(-1, 1)), - new Movement(1, Direction.valueOf(-1, 1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(1, Direction.valueOf(1, 1)), - new Movement(1, Direction.valueOf(1, 1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(-1, 0)), - new Movement(1, Direction.valueOf(-1, 1)), - new Movement(1, Direction.valueOf(-1, 1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(-1, 0)), - new Movement(1, Direction.valueOf(-1, -1)), - new Movement(1, Direction.valueOf(-1, -1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, -1)), - new Movement(1, Direction.valueOf(-1, -1)), - new Movement(1, Direction.valueOf(-1, -1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, -1)), - new Movement(1, Direction.valueOf(1, -1)), - new Movement(1, Direction.valueOf(1, -1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(1, 0)), - new Movement(1, Direction.valueOf(1, -1)), - new Movement(1, Direction.valueOf(1, -1)))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(1, 0)), - new Movement(1, Direction.valueOf(1, 1)), - new Movement(1, Direction.valueOf(1, 1))) - )); + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, 1)), + new Movement(1, Direction.valueOf(-1, 1)), + new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, 1)), + new Movement(1, Direction.valueOf(1, 1)), + new Movement(1, Direction.valueOf(1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(-1, 0)), + new Movement(1, Direction.valueOf(-1, 1)), + new Movement(1, Direction.valueOf(-1, 1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(-1, 0)), + new Movement(1, Direction.valueOf(-1, -1)), + new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, -1)), + new Movement(1, Direction.valueOf(-1, -1)), + new Movement(1, Direction.valueOf(-1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(0, -1)), + new Movement(1, Direction.valueOf(1, -1)), + new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(1, 0)), + new Movement(1, Direction.valueOf(1, -1)), + new Movement(1, Direction.valueOf(1, -1)))), + new RuleWithNoTraces(List.of( + new Movement(1, Direction.valueOf(1, 0)), + new Movement(1, Direction.valueOf(1, 1)), + new Movement(1, Direction.valueOf(1, 1))) + )); PIECE_ACTION = new PieceAction(rules); } @@ -78,13 +77,13 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(final Position from, - final BoardMediator boardMediator) { + final BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } @Override public boolean canKill(final Piece target) { return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( - teamType); + teamType); } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index f56fd0cc83..97b76ceb93 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 0c3e30534f..702cdf9da8 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 3524e5d7bd..d8f92aeb83 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 2e5583d1e8..9f25e3aa52 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; diff --git a/src/main/java/janggi/domain/PieceType.java b/src/main/java/janggi/domain/piece/PieceType.java similarity index 63% rename from src/main/java/janggi/domain/PieceType.java rename to src/main/java/janggi/domain/piece/PieceType.java index b55d049a5a..75cc2780b8 100644 --- a/src/main/java/janggi/domain/PieceType.java +++ b/src/main/java/janggi/domain/piece/PieceType.java @@ -1,13 +1,5 @@ -package janggi.domain; +package janggi.domain.piece; -import janggi.domain.piece.Cannon; -import janggi.domain.piece.Chariot; -import janggi.domain.piece.Elephant; -import janggi.domain.piece.General; -import janggi.domain.piece.Guard; -import janggi.domain.piece.Horse; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.function.Function; @@ -22,7 +14,7 @@ public enum PieceType { SOLDIER(Soldier::new); private final Function function; - + PieceType(Function function) { this.function = function; } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index eef897c257..eeb4b44634 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; diff --git a/src/main/java/janggi/domain/InnerElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/InnerElephantSetupPolicy.java similarity index 85% rename from src/main/java/janggi/domain/InnerElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/InnerElephantSetupPolicy.java index 027d8b7b29..fc5fbf65cd 100644 --- a/src/main/java/janggi/domain/InnerElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/InnerElephantSetupPolicy.java @@ -1,5 +1,7 @@ -package janggi.domain; +package janggi.domain.setup; +import janggi.domain.piece.PieceType; +import janggi.domain.Position; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/LeftElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/LeftElephantSetupPolicy.java similarity index 85% rename from src/main/java/janggi/domain/LeftElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/LeftElephantSetupPolicy.java index 54c6b0baac..5268228e49 100644 --- a/src/main/java/janggi/domain/LeftElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/LeftElephantSetupPolicy.java @@ -1,5 +1,7 @@ -package janggi.domain; +package janggi.domain.setup; +import janggi.domain.piece.PieceType; +import janggi.domain.Position; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/OuterElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/OuterElephantSetupPolicy.java similarity index 85% rename from src/main/java/janggi/domain/OuterElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/OuterElephantSetupPolicy.java index 70f986b961..89349a710b 100644 --- a/src/main/java/janggi/domain/OuterElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/OuterElephantSetupPolicy.java @@ -1,5 +1,7 @@ -package janggi.domain; +package janggi.domain.setup; +import janggi.domain.Position; +import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/RightElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/RightElephantSetupPolicy.java similarity index 85% rename from src/main/java/janggi/domain/RightElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/RightElephantSetupPolicy.java index 98b7755098..d66eac2d97 100644 --- a/src/main/java/janggi/domain/RightElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/RightElephantSetupPolicy.java @@ -1,5 +1,7 @@ -package janggi.domain; +package janggi.domain.setup; +import janggi.domain.Position; +import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/SetupPolicy.java b/src/main/java/janggi/domain/setup/SetupPolicy.java similarity index 92% rename from src/main/java/janggi/domain/SetupPolicy.java rename to src/main/java/janggi/domain/setup/SetupPolicy.java index 39417ab2a5..004d3540f9 100644 --- a/src/main/java/janggi/domain/SetupPolicy.java +++ b/src/main/java/janggi/domain/setup/SetupPolicy.java @@ -1,5 +1,7 @@ -package janggi.domain; +package janggi.domain.setup; +import janggi.domain.Position; +import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java index 81920d5b45..dff234a40b 100644 --- a/src/main/java/janggi/domain/team/BlueTeam.java +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -1,8 +1,8 @@ package janggi.domain.team; -import janggi.domain.PieceType; +import janggi.domain.piece.PieceType; import janggi.domain.Position; -import janggi.domain.SetupPolicy; +import janggi.domain.setup.SetupPolicy; import janggi.domain.piece.Piece; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java index dbfdaea391..287ec56d84 100644 --- a/src/main/java/janggi/domain/team/RedTeam.java +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -1,8 +1,8 @@ package janggi.domain.team; -import janggi.domain.PieceType; +import janggi.domain.piece.PieceType; import janggi.domain.Position; -import janggi.domain.SetupPolicy; +import janggi.domain.setup.SetupPolicy; import janggi.domain.piece.Piece; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java index 14917adaa9..6f05a8c871 100644 --- a/src/main/java/janggi/dto/BoardDto.java +++ b/src/main/java/janggi/dto/BoardDto.java @@ -5,10 +5,10 @@ import static janggi.domain.Position.MINIMUM_COLUMN; import static janggi.domain.Position.MINIMUM_ROW; -import janggi.domain.PieceType; import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import janggi.domain.team.TeamType; import janggi.view.ConsoleColor; import java.util.ArrayList; @@ -16,7 +16,7 @@ import java.util.Map; public record BoardDto( - List rowStatuses + List rowStatuses ) { private static final Map> CHINESE_MAP; @@ -25,24 +25,24 @@ public record BoardDto( static { CHINESE_MAP = Map.of( - TeamType.RED, Map.of( - PieceType.GENERAL, ConsoleColor.red("漢"), - PieceType.GUARD, ConsoleColor.red("士"), - PieceType.CHARIOT, ConsoleColor.red("車"), - PieceType.CANNON, ConsoleColor.red("包"), - PieceType.HORSE, ConsoleColor.red("馬"), - PieceType.ELEPHANT, ConsoleColor.red("象"), - PieceType.SOLDIER, ConsoleColor.red("兵") - ), - TeamType.BLUE, Map.of( - PieceType.GENERAL, ConsoleColor.blue("楚"), - PieceType.GUARD, ConsoleColor.blue("士"), - PieceType.CHARIOT, ConsoleColor.blue("車"), - PieceType.CANNON, ConsoleColor.blue("包"), - PieceType.HORSE, ConsoleColor.blue("馬"), - PieceType.ELEPHANT, ConsoleColor.blue("象"), - PieceType.SOLDIER, ConsoleColor.blue("卒") - )); + TeamType.RED, Map.of( + PieceType.GENERAL, ConsoleColor.red("漢"), + PieceType.GUARD, ConsoleColor.red("士"), + PieceType.CHARIOT, ConsoleColor.red("車"), + PieceType.CANNON, ConsoleColor.red("包"), + PieceType.HORSE, ConsoleColor.red("馬"), + PieceType.ELEPHANT, ConsoleColor.red("象"), + PieceType.SOLDIER, ConsoleColor.red("兵") + ), + TeamType.BLUE, Map.of( + PieceType.GENERAL, ConsoleColor.blue("楚"), + PieceType.GUARD, ConsoleColor.blue("士"), + PieceType.CHARIOT, ConsoleColor.blue("車"), + PieceType.CANNON, ConsoleColor.blue("包"), + PieceType.HORSE, ConsoleColor.blue("馬"), + PieceType.ELEPHANT, ConsoleColor.blue("象"), + PieceType.SOLDIER, ConsoleColor.blue("卒") + )); } public static BoardDto from(final Board board) { diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index d1f0e27910..b386985ec5 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -1,13 +1,9 @@ package janggi.view; -import janggi.domain.Position; -import janggi.domain.board.Board; import janggi.domain.command.SetupCommand; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import janggi.dto.BoardDto; import java.util.List; -import java.util.Map; public final class OutputView { private static final String ERROR_PREFIX = "[ERROR]: "; diff --git a/src/test/java/janggi/domain/BoardGeneratorTest.java b/src/test/java/janggi/domain/BoardGeneratorTest.java index c1ed295bf8..d912d19308 100644 --- a/src/test/java/janggi/domain/BoardGeneratorTest.java +++ b/src/test/java/janggi/domain/BoardGeneratorTest.java @@ -4,6 +4,7 @@ import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; +import janggi.domain.setup.InnerElephantSetupPolicy; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import org.assertj.core.api.InstanceOfAssertFactories; diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index d7aa6cb201..39e0d7821d 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,6 +1,5 @@ package janggi.domain; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -37,7 +36,7 @@ void success_1() { void success_2() { Position position = Position.valueOf(1, 1); Map positionPieceMap = Map.of( - position, new Cannon(TeamType.RED)); + position, new Cannon(TeamType.RED)); Board board = new Board(positionPieceMap); boolean expected = false; @@ -57,13 +56,13 @@ void success() { Position position = Position.valueOf(1, 1); Piece expected = new Cannon(TeamType.RED); Map positionPieceMap = Map.of( - position, expected); + position, expected); Board board = new Board(positionPieceMap); Piece actual = board.findPieceByPosition(position); assertThat(actual).usingRecursiveComparison() - .isEqualTo(expected); + .isEqualTo(expected); } @Test @@ -73,7 +72,7 @@ void failure() { Board board = new Board(new LinkedHashMap<>()); assertThatIllegalStateException() - .isThrownBy(() -> board.findPieceByPosition(position)); + .isThrownBy(() -> board.findPieceByPosition(position)); } } } diff --git a/src/test/java/janggi/domain/CannonTest.java b/src/test/java/janggi/domain/CannonTest.java index 5bcb0431f5..05b64fbb73 100644 --- a/src/test/java/janggi/domain/CannonTest.java +++ b/src/test/java/janggi/domain/CannonTest.java @@ -42,22 +42,22 @@ void setUp() { @DisplayName("포는 기물을 뛰어 넘어서 이동할 수 있다.") void success_1() { positionPieceMap = Map.of( - Position.valueOf(6, 7), cannon, - Position.valueOf(6, 5), enemySoldier, - Position.valueOf(7, 7), allySoldier); + Position.valueOf(6, 7), cannon, + Position.valueOf(6, 5), enemySoldier, + Position.valueOf(7, 7), allySoldier); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List expected = List.of( - Position.valueOf(6, 1), - Position.valueOf(6, 2), - Position.valueOf(6, 3), - Position.valueOf(6, 4), - Position.valueOf(8, 7), - Position.valueOf(9, 7), - Position.valueOf(10, 7)); + Position.valueOf(6, 1), + Position.valueOf(6, 2), + Position.valueOf(6, 3), + Position.valueOf(6, 4), + Position.valueOf(8, 7), + Position.valueOf(9, 7), + Position.valueOf(10, 7)); List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -66,19 +66,19 @@ void success_1() { @DisplayName("포는 포를 넘을 수 없다.") void success_2() { positionPieceMap = Map.of( - Position.valueOf(6, 7), cannon, - Position.valueOf(4, 7), enemySoldier, - Position.valueOf(6, 5), enemyCannon, - Position.valueOf(9, 7), allyCannon); + Position.valueOf(6, 7), cannon, + Position.valueOf(4, 7), enemySoldier, + Position.valueOf(6, 5), enemyCannon, + Position.valueOf(9, 7), allyCannon); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List expected = List.of( - Position.valueOf(1, 7), - Position.valueOf(2, 7), - Position.valueOf(3, 7)); + Position.valueOf(1, 7), + Position.valueOf(2, 7), + Position.valueOf(3, 7)); List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -87,15 +87,15 @@ void success_2() { @DisplayName("포는 포를 잡을 수 없다.") void success_3() { positionPieceMap = Map.of( - Position.valueOf(6, 7), cannon, - Position.valueOf(6, 3), enemyCannon, - Position.valueOf(6, 4), allySoldier); + Position.valueOf(6, 7), cannon, + Position.valueOf(6, 3), enemyCannon, + Position.valueOf(6, 4), allySoldier); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List expected = List.of(); List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/GuardTest.java b/src/test/java/janggi/domain/GuardTest.java index a38e44df66..453bbb40a5 100644 --- a/src/test/java/janggi/domain/GuardTest.java +++ b/src/test/java/janggi/domain/GuardTest.java @@ -62,12 +62,12 @@ void test1() { positionPieceMap.put(Position.valueOf(7, 5), enemy4); List expected = List.of(Position.valueOf(6, 5), Position.valueOf(7, 3), - Position.valueOf(7, 4), Position.valueOf(7, 5)); + Position.valueOf(7, 4), Position.valueOf(7, 5)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -79,13 +79,13 @@ void test2() { positionPieceMap.put(Position.valueOf(6, 5), enemy1); positionPieceMap.put(Position.valueOf(7, 3), enemy2); List expected = List.of(Position.valueOf(5, 3), Position.valueOf(5, 4), - Position.valueOf(5, 5), Position.valueOf(6, 3), Position.valueOf(6, 5), Position.valueOf(7, 3), - Position.valueOf(7, 4), Position.valueOf(7, 5)); + Position.valueOf(5, 5), Position.valueOf(6, 3), Position.valueOf(6, 5), Position.valueOf(7, 3), + Position.valueOf(7, 4), Position.valueOf(7, 5)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -102,7 +102,7 @@ void test3() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = guard.calculateMovablePositions(Position.valueOf(1, 1), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/HorseTest.java b/src/test/java/janggi/domain/HorseTest.java index 16d399cfa2..0c8422cb40 100644 --- a/src/test/java/janggi/domain/HorseTest.java +++ b/src/test/java/janggi/domain/HorseTest.java @@ -61,7 +61,7 @@ void test1() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -73,14 +73,14 @@ void test2() { positionPieceMap.put(Position.valueOf(5, 6), enemy1); positionPieceMap.put(Position.valueOf(7, 2), enemy2); List expected = List.of(Position.valueOf(4, 3), Position.valueOf(4, 5), - Position.valueOf(5, 6), Position.valueOf(7, 6), - Position.valueOf(8, 3), Position.valueOf(8, 5), Position.valueOf(7, 2), - Position.valueOf(5, 2)); + Position.valueOf(5, 6), Position.valueOf(7, 6), + Position.valueOf(8, 3), Position.valueOf(8, 5), Position.valueOf(7, 2), + Position.valueOf(5, 2)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } @@ -96,7 +96,7 @@ void test3() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = horse.calculateMovablePositions(Position.valueOf(1, 1), - boardMediator); + boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java b/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java index 538fd8dc31..d8172a36cb 100644 --- a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.PieceType; +import janggi.domain.setup.InnerElephantSetupPolicy; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java b/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java index 752fa4b613..412cc7614e 100644 --- a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.PieceType; +import janggi.domain.setup.LeftElephantSetupPolicy; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java b/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java index 3de58f55d5..debe81901e 100644 --- a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.PieceType; +import janggi.domain.setup.OuterElephantSetupPolicy; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java b/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java index 135e999b06..23c54b2d90 100644 --- a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.PieceType; +import janggi.domain.setup.RightElephantSetupPolicy; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java b/src/test/java/janggi/domain/movement/RuleOfCannonTest.java index 2dfa7d3526..b1fedb0b0c 100644 --- a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java +++ b/src/test/java/janggi/domain/movement/RuleOfCannonTest.java @@ -1,6 +1,5 @@ package janggi.domain.movement; -import static janggi.domain.Position.MAXIMUM_ROW; import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.Position; diff --git a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java b/src/test/java/janggi/fixture/SetupPolicyTestFixture.java index afda1c6d0f..dfcf109358 100644 --- a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java +++ b/src/test/java/janggi/fixture/SetupPolicyTestFixture.java @@ -1,6 +1,6 @@ package janggi.fixture; -import janggi.domain.PieceType; +import janggi.domain.piece.PieceType; import janggi.domain.Position; import java.util.LinkedHashMap; import java.util.Map; From efb36809fca6cb692ed49b7c89b7966b2e42b961 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 28 Mar 2026 23:01:29 +0900 Subject: [PATCH 062/128] =?UTF-8?q?refactor:=20=EC=98=A4=ED=83=80=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/janggi/domain/command/SetupCommand.java | 4 ++-- src/main/java/janggi/domain/movement/Direction.java | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/janggi/domain/command/SetupCommand.java b/src/main/java/janggi/domain/command/SetupCommand.java index c6be565a1d..b54af8d61e 100644 --- a/src/main/java/janggi/domain/command/SetupCommand.java +++ b/src/main/java/janggi/domain/command/SetupCommand.java @@ -15,7 +15,7 @@ public enum SetupCommand { LEFT_ELEPHANT(3, "왼상 차림", LeftElephantSetupPolicy::new), RIGHT_ELEPHANT(4, "오른상 차림", RightElephantSetupPolicy::new); - private static final int MINUMUM_NUMBER = 1; + private static final int MINIMUM_NUMBER = 1; private static final int MAXIMUM_NUMBER = 4; private final int number; @@ -33,7 +33,7 @@ public static SetupCommand pick(final int number) { .filter(setupCommand -> setupCommand.number == number) .findFirst() .orElseThrow(() -> new IllegalArgumentException(String.format( - "명령 번호는 %d에서 %d까지의 정수 값이어야 합니다.", MINUMUM_NUMBER, MAXIMUM_NUMBER))); + "명령 번호는 %d에서 %d까지의 정수 값이어야 합니다.", MINIMUM_NUMBER, MAXIMUM_NUMBER))); } public SetupPolicy toPolicy() { diff --git a/src/main/java/janggi/domain/movement/Direction.java b/src/main/java/janggi/domain/movement/Direction.java index c11ea92017..5a95389635 100644 --- a/src/main/java/janggi/domain/movement/Direction.java +++ b/src/main/java/janggi/domain/movement/Direction.java @@ -2,7 +2,6 @@ import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.stream.IntStream; public final class Direction { @@ -16,7 +15,7 @@ public final class Direction { static { CACHE = new LinkedHashMap<>(); IntStream.range(MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION + 1) - .forEach(rowDirection -> CACHE.put(rowDirection, new LinkedHashMap<>())); + .forEach(rowDirection -> CACHE.put(rowDirection, new LinkedHashMap<>())); } private final int rowDirection; @@ -41,16 +40,15 @@ public static Direction valueOf(final int rowDirection, final int columnDirectio private static void validateRowDirectionRange(final int rowDirection) { if (rowDirection < MINIMUM_ROW_DIRECTION || rowDirection > MAXIMUM_ROW_DIRECTION) { throw new IllegalArgumentException(String.format( - "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_ROW_DIRECTION, MAXIMUM_ROW_DIRECTION)); + "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_ROW_DIRECTION, MAXIMUM_ROW_DIRECTION)); } } private static void validateColumnDirectionRange(final int columnDirection) { if (columnDirection < MINIMUM_COLUMN_DIRECTION - || columnDirection > MAXIMUM_COLUMN_DIRECTION) { + || columnDirection > MAXIMUM_COLUMN_DIRECTION) { throw new IllegalArgumentException(String.format( - "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_COLUMN_DIRECTION, - MAXIMUM_COLUMN_DIRECTION)); + "열 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION)); } } From ee3f7f9a344e84917d565205396366498b1d8246 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 00:14:54 +0900 Subject: [PATCH 063/128] =?UTF-8?q?refactor:=20SetupCommand=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 입력값 검증을 InputView로 분리 - 입력 예외테스트는 제거 --- .../janggi/controller/JanggiController.java | 4 +- .../janggi/domain/command/SetupCommand.java | 50 +++++-------------- src/main/java/janggi/view/InputView.java | 11 +++- src/main/java/janggi/view/OutputView.java | 12 +++-- .../java/janggi/domain/SetupCommandTest.java | 18 ------- 5 files changed, 33 insertions(+), 62 deletions(-) delete mode 100644 src/test/java/janggi/domain/SetupCommandTest.java diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 028812ea48..1da6a38b93 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -39,7 +39,7 @@ public void run() { } private SetupCommand readSetupCommand() { - int commandNumber = InputView.readSetupCommand(); - return SetupCommand.pick(commandNumber); + int inputCommand = InputView.readSetupCommand(); + return SetupCommand.values()[inputCommand - 1]; } } diff --git a/src/main/java/janggi/domain/command/SetupCommand.java b/src/main/java/janggi/domain/command/SetupCommand.java index b54af8d61e..1647d272e1 100644 --- a/src/main/java/janggi/domain/command/SetupCommand.java +++ b/src/main/java/janggi/domain/command/SetupCommand.java @@ -1,50 +1,26 @@ package janggi.domain.command; -import janggi.domain.setup.InnerElephantSetupPolicy; -import janggi.domain.setup.LeftElephantSetupPolicy; -import janggi.domain.setup.OuterElephantSetupPolicy; -import janggi.domain.setup.RightElephantSetupPolicy; -import janggi.domain.setup.SetupPolicy; -import java.util.Arrays; +import janggi.domain.setup.ElephantFormation; +import janggi.domain.setup.InnerElephantElephantFormation; +import janggi.domain.setup.LeftElephantElephantFormation; +import janggi.domain.setup.OuterElephantElephantFormation; +import janggi.domain.setup.RightElephantElephantFormation; import java.util.function.Supplier; public enum SetupCommand { - INNER_ELEPHANT(1, "안상 차림", InnerElephantSetupPolicy::new), - OUTER_ELEPHANT(2, "바깥상 차림", OuterElephantSetupPolicy::new), - LEFT_ELEPHANT(3, "왼상 차림", LeftElephantSetupPolicy::new), - RIGHT_ELEPHANT(4, "오른상 차림", RightElephantSetupPolicy::new); + INNER_ELEPHANT(InnerElephantElephantFormation::new), + OUTER_ELEPHANT(OuterElephantElephantFormation::new), + LEFT_ELEPHANT(LeftElephantElephantFormation::new), + RIGHT_ELEPHANT(RightElephantElephantFormation::new); + + private final Supplier policySupplier; - private static final int MINIMUM_NUMBER = 1; - private static final int MAXIMUM_NUMBER = 4; - - private final int number; - private final String description; - private final Supplier policySupplier; - - SetupCommand(final int number, final String description, final Supplier setupPolicySupplier) { - this.number = number; - this.description = description; + SetupCommand(final Supplier setupPolicySupplier) { this.policySupplier = setupPolicySupplier; } - public static SetupCommand pick(final int number) { - return Arrays.stream(values()) - .filter(setupCommand -> setupCommand.number == number) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException(String.format( - "명령 번호는 %d에서 %d까지의 정수 값이어야 합니다.", MINIMUM_NUMBER, MAXIMUM_NUMBER))); - } - - public SetupPolicy toPolicy() { + public ElephantFormation toPolicy() { return policySupplier.get(); } - - public int getNumber() { - return number; - } - - public String getDescription() { - return description; - } } diff --git a/src/main/java/janggi/view/InputView.java b/src/main/java/janggi/view/InputView.java index e54aa007ec..5ed047a2d0 100644 --- a/src/main/java/janggi/view/InputView.java +++ b/src/main/java/janggi/view/InputView.java @@ -4,10 +4,19 @@ import janggi.view.reader.Console; public final class InputView { + + private static final int MIN_SETUP_COMMAND = 1; + private static final int MAX_SETUP_COMMAND = 4; + private InputView() { } public static int readSetupCommand() { - return Parser.parseInteger(Console.readLine()); + int inputCommand = Parser.parseInteger(Console.readLine()); + if (inputCommand >= MIN_SETUP_COMMAND && inputCommand <= MAX_SETUP_COMMAND) { + return inputCommand; + } + throw new IllegalArgumentException( + "명령 번호는 " + MIN_SETUP_COMMAND + "에서 " + MAX_SETUP_COMMAND + "까지의 정수 값이어야 합니다."); } } diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index b386985ec5..ceaebe78b4 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -1,20 +1,25 @@ package janggi.view; -import janggi.domain.command.SetupCommand; import janggi.domain.team.TeamType; import janggi.dto.BoardDto; import java.util.List; public final class OutputView { private static final String ERROR_PREFIX = "[ERROR]: "; + private static final List ELEPHANT_FORMATION_DESCRIPTIONS = List.of( + "1. 안상 차림", + "2. 바깥상 차림", + "3. 왼상 차림", + "4. 오른상 차림" + ); private OutputView() { } public static void printSetupGuide(TeamType teamType) { System.out.println(teamType.getName() + "의 차림법을 입력해주세요."); - for (final SetupCommand setupCommand : SetupCommand.values()) { - System.out.println(setupCommand.getNumber() + ". " + setupCommand.getDescription()); + for (final String description : ELEPHANT_FORMATION_DESCRIPTIONS) { + System.out.println(description); } } @@ -24,7 +29,6 @@ public static void printErrorMessage(String message) { public static void printBoard(final BoardDto boardDto) { final List rowStatuses = boardDto.rowStatuses(); - for (String rowStatus : rowStatuses) { System.out.println(rowStatus); } diff --git a/src/test/java/janggi/domain/SetupCommandTest.java b/src/test/java/janggi/domain/SetupCommandTest.java deleted file mode 100644 index 442e704f9e..0000000000 --- a/src/test/java/janggi/domain/SetupCommandTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package janggi.domain; - -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -import janggi.domain.command.SetupCommand; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -public class SetupCommandTest { - - @Test - @DisplayName("차림판 예외 테스트") - void failure() { - int wrongNumber = 5; - assertThatIllegalArgumentException() - .isThrownBy(() -> SetupCommand.pick(wrongNumber)); - } -} From d86f2719ef18a8cb4a1c11bdc6e221fb97afb279 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 00:16:56 +0900 Subject: [PATCH 064/128] =?UTF-8?q?refactor:=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 SetupPolicy -> ElephantFormation --- .../java/janggi/controller/JanggiController.java | 10 +++++----- .../{SetupPolicy.java => ElephantFormation.java} | 2 +- ...licy.java => InnerElephantElephantFormation.java} | 4 ++-- ...olicy.java => LeftElephantElephantFormation.java} | 4 ++-- ...licy.java => OuterElephantElephantFormation.java} | 2 +- ...licy.java => RightElephantElephantFormation.java} | 2 +- src/main/java/janggi/domain/team/BlueTeam.java | 12 ++++++------ src/main/java/janggi/domain/team/RedTeam.java | 12 ++++++------ src/test/java/janggi/domain/BoardGeneratorTest.java | 6 +++--- ....java => InnerElephantElephantFormationTest.java} | 6 +++--- ...t.java => LeftElephantElephantFormationTest.java} | 6 +++--- ....java => OuterElephantElephantFormationTest.java} | 6 +++--- ....java => RightElephantElephantFormationTest.java} | 6 +++--- 13 files changed, 39 insertions(+), 39 deletions(-) rename src/main/java/janggi/domain/setup/{SetupPolicy.java => ElephantFormation.java} (96%) rename src/main/java/janggi/domain/setup/{InnerElephantSetupPolicy.java => InnerElephantElephantFormation.java} (89%) rename src/main/java/janggi/domain/setup/{LeftElephantSetupPolicy.java => LeftElephantElephantFormation.java} (89%) rename src/main/java/janggi/domain/setup/{OuterElephantSetupPolicy.java => OuterElephantElephantFormation.java} (89%) rename src/main/java/janggi/domain/setup/{RightElephantSetupPolicy.java => RightElephantElephantFormation.java} (89%) rename src/test/java/janggi/domain/{InnerElephantSetupPolicyTest.java => InnerElephantElephantFormationTest.java} (83%) rename src/test/java/janggi/domain/{LeftElephantSetupPolicyTest.java => LeftElephantElephantFormationTest.java} (83%) rename src/test/java/janggi/domain/{OuterElephantSetupPolicyTest.java => OuterElephantElephantFormationTest.java} (83%) rename src/test/java/janggi/domain/{RightElephantSetupPolicyTest.java => RightElephantElephantFormationTest.java} (83%) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 1da6a38b93..35ae0c7fa4 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -3,7 +3,7 @@ import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; import janggi.domain.command.SetupCommand; -import janggi.domain.setup.SetupPolicy; +import janggi.domain.setup.ElephantFormation; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import janggi.domain.team.Team; @@ -20,15 +20,15 @@ public JanggiController() { private Team setupRedTeam() { OutputView.printSetupGuide(TeamType.RED); final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); - final SetupPolicy setupPolicy = setupCommand.toPolicy(); - return new RedTeam(setupPolicy); + final ElephantFormation elephantFormation = setupCommand.toPolicy(); + return new RedTeam(elephantFormation); } private Team setupBlueTeam() { OutputView.printSetupGuide(TeamType.BLUE); final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); - final SetupPolicy setupPolicy = setupCommand.toPolicy(); - return new BlueTeam(setupPolicy); + final ElephantFormation elephantFormation = setupCommand.toPolicy(); + return new BlueTeam(elephantFormation); } public void run() { diff --git a/src/main/java/janggi/domain/setup/SetupPolicy.java b/src/main/java/janggi/domain/setup/ElephantFormation.java similarity index 96% rename from src/main/java/janggi/domain/setup/SetupPolicy.java rename to src/main/java/janggi/domain/setup/ElephantFormation.java index 004d3540f9..d00bfb2fb8 100644 --- a/src/main/java/janggi/domain/setup/SetupPolicy.java +++ b/src/main/java/janggi/domain/setup/ElephantFormation.java @@ -5,7 +5,7 @@ import java.util.LinkedHashMap; import java.util.Map; -public abstract class SetupPolicy { +public abstract class ElephantFormation { static final Map COMMON_BOARD_MAP; static { diff --git a/src/main/java/janggi/domain/setup/InnerElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java similarity index 89% rename from src/main/java/janggi/domain/setup/InnerElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java index fc5fbf65cd..8fa3e36731 100644 --- a/src/main/java/janggi/domain/setup/InnerElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java @@ -1,11 +1,11 @@ package janggi.domain.setup; -import janggi.domain.piece.PieceType; import janggi.domain.Position; +import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; import java.util.Map; -public class InnerElephantSetupPolicy extends SetupPolicy { +public class InnerElephantElephantFormation extends ElephantFormation { @Override public Map offerBoardMap() { diff --git a/src/main/java/janggi/domain/setup/LeftElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java similarity index 89% rename from src/main/java/janggi/domain/setup/LeftElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java index 5268228e49..3a1f6a6ab0 100644 --- a/src/main/java/janggi/domain/setup/LeftElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java @@ -1,11 +1,11 @@ package janggi.domain.setup; -import janggi.domain.piece.PieceType; import janggi.domain.Position; +import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; import java.util.Map; -public class LeftElephantSetupPolicy extends SetupPolicy { +public class LeftElephantElephantFormation extends ElephantFormation { @Override public Map offerBoardMap() { final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); diff --git a/src/main/java/janggi/domain/setup/OuterElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java similarity index 89% rename from src/main/java/janggi/domain/setup/OuterElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java index 89349a710b..5470397227 100644 --- a/src/main/java/janggi/domain/setup/OuterElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java @@ -5,7 +5,7 @@ import java.util.LinkedHashMap; import java.util.Map; -public class OuterElephantSetupPolicy extends SetupPolicy { +public class OuterElephantElephantFormation extends ElephantFormation { @Override public Map offerBoardMap() { final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); diff --git a/src/main/java/janggi/domain/setup/RightElephantSetupPolicy.java b/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java similarity index 89% rename from src/main/java/janggi/domain/setup/RightElephantSetupPolicy.java rename to src/main/java/janggi/domain/setup/RightElephantElephantFormation.java index d66eac2d97..3febdc2fa7 100644 --- a/src/main/java/janggi/domain/setup/RightElephantSetupPolicy.java +++ b/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java @@ -5,7 +5,7 @@ import java.util.LinkedHashMap; import java.util.Map; -public class RightElephantSetupPolicy extends SetupPolicy { +public class RightElephantElephantFormation extends ElephantFormation { @Override public Map offerBoardMap() { final Map boardMap = new LinkedHashMap<>(COMMON_BOARD_MAP); diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java index dff234a40b..ff4c30d148 100644 --- a/src/main/java/janggi/domain/team/BlueTeam.java +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -1,25 +1,25 @@ package janggi.domain.team; -import janggi.domain.piece.PieceType; import janggi.domain.Position; -import janggi.domain.setup.SetupPolicy; import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; +import janggi.domain.setup.ElephantFormation; import java.util.LinkedHashMap; import java.util.Map; public class BlueTeam implements Team { private static final TeamType TEAM_TYPE = TeamType.BLUE; - private final SetupPolicy setupPolicy; + private final ElephantFormation elephantFormation; - public BlueTeam(final SetupPolicy setupPolicy) { - this.setupPolicy = setupPolicy; + public BlueTeam(final ElephantFormation elephantFormation) { + this.elephantFormation = elephantFormation; } @Override public Map generatePieces() { final Map positionPieceMap = new LinkedHashMap<>(); - final Map positionPieceTypeMap = setupPolicy.offerBoardMap(); + final Map positionPieceTypeMap = elephantFormation.offerBoardMap(); positionPieceTypeMap.forEach((position, pieceType) -> positionPieceMap.put(position.flipAroundMiddleRow(), pieceType.toPiece(TEAM_TYPE))); diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java index 287ec56d84..7c6ccf8604 100644 --- a/src/main/java/janggi/domain/team/RedTeam.java +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -1,26 +1,26 @@ package janggi.domain.team; -import janggi.domain.piece.PieceType; import janggi.domain.Position; -import janggi.domain.setup.SetupPolicy; import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; +import janggi.domain.setup.ElephantFormation; import java.util.LinkedHashMap; import java.util.Map; public class RedTeam implements Team { private static final TeamType TEAM_TYPE = TeamType.RED; - private final SetupPolicy setupPolicy; + private final ElephantFormation elephantFormation; - public RedTeam(final SetupPolicy setupPolicy) { - this.setupPolicy = setupPolicy; + public RedTeam(final ElephantFormation elephantFormation) { + this.elephantFormation = elephantFormation; } @Override public Map generatePieces() { final Map positionPieceMap = new LinkedHashMap<>(); - final Map positionPieceTypeMap = setupPolicy.offerBoardMap(); + final Map positionPieceTypeMap = elephantFormation.offerBoardMap(); positionPieceTypeMap.forEach((position, pieceType) -> positionPieceMap.put(position, pieceType.toPiece(TEAM_TYPE))); diff --git a/src/test/java/janggi/domain/BoardGeneratorTest.java b/src/test/java/janggi/domain/BoardGeneratorTest.java index d912d19308..5dfbce76d3 100644 --- a/src/test/java/janggi/domain/BoardGeneratorTest.java +++ b/src/test/java/janggi/domain/BoardGeneratorTest.java @@ -4,7 +4,7 @@ import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; -import janggi.domain.setup.InnerElephantSetupPolicy; +import janggi.domain.setup.InnerElephantElephantFormation; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import org.assertj.core.api.InstanceOfAssertFactories; @@ -17,8 +17,8 @@ public class BoardGeneratorTest { @DisplayName("보드판 기물 정상 테스트") void success() { // given - RedTeam redTeam = new RedTeam(new InnerElephantSetupPolicy()); - BlueTeam blueTeam = new BlueTeam(new InnerElephantSetupPolicy()); + RedTeam redTeam = new RedTeam(new InnerElephantElephantFormation()); + BlueTeam blueTeam = new BlueTeam(new InnerElephantElephantFormation()); final int expected = 32; // when diff --git a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java b/src/test/java/janggi/domain/InnerElephantElephantFormationTest.java similarity index 83% rename from src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java rename to src/test/java/janggi/domain/InnerElephantElephantFormationTest.java index d8172a36cb..bb2ad0dd6a 100644 --- a/src/test/java/janggi/domain/InnerElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/InnerElephantElephantFormationTest.java @@ -3,19 +3,19 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.piece.PieceType; -import janggi.domain.setup.InnerElephantSetupPolicy; +import janggi.domain.setup.InnerElephantElephantFormation; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class InnerElephantSetupPolicyTest { +class InnerElephantElephantFormationTest { @Test @DisplayName("안상 차림 테스트") void setUp() { - InnerElephantSetupPolicy policy = new InnerElephantSetupPolicy(); + InnerElephantElephantFormation policy = new InnerElephantElephantFormation(); Map expected = new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.HORSE); diff --git a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java b/src/test/java/janggi/domain/LeftElephantElephantFormationTest.java similarity index 83% rename from src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java rename to src/test/java/janggi/domain/LeftElephantElephantFormationTest.java index 412cc7614e..8e91cb65ac 100644 --- a/src/test/java/janggi/domain/LeftElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/LeftElephantElephantFormationTest.java @@ -3,19 +3,19 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.piece.PieceType; -import janggi.domain.setup.LeftElephantSetupPolicy; +import janggi.domain.setup.LeftElephantElephantFormation; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -public class LeftElephantSetupPolicyTest { +public class LeftElephantElephantFormationTest { @Test @DisplayName("왼상 차림 테스트") void setUp() { - LeftElephantSetupPolicy policy = new LeftElephantSetupPolicy(); + LeftElephantElephantFormation policy = new LeftElephantElephantFormation(); Map expected = new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.ELEPHANT); diff --git a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java b/src/test/java/janggi/domain/OuterElephantElephantFormationTest.java similarity index 83% rename from src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java rename to src/test/java/janggi/domain/OuterElephantElephantFormationTest.java index debe81901e..dbe57bfadf 100644 --- a/src/test/java/janggi/domain/OuterElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/OuterElephantElephantFormationTest.java @@ -3,19 +3,19 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.piece.PieceType; -import janggi.domain.setup.OuterElephantSetupPolicy; +import janggi.domain.setup.OuterElephantElephantFormation; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class OuterElephantSetupPolicyTest { +class OuterElephantElephantFormationTest { @Test @DisplayName("바깥상 차림 테스트") void setUp() { - OuterElephantSetupPolicy policy = new OuterElephantSetupPolicy(); + OuterElephantElephantFormation policy = new OuterElephantElephantFormation(); Map expected = new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.ELEPHANT); diff --git a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java b/src/test/java/janggi/domain/RightElephantElephantFormationTest.java similarity index 83% rename from src/test/java/janggi/domain/RightElephantSetupPolicyTest.java rename to src/test/java/janggi/domain/RightElephantElephantFormationTest.java index 23c54b2d90..aeecf765db 100644 --- a/src/test/java/janggi/domain/RightElephantSetupPolicyTest.java +++ b/src/test/java/janggi/domain/RightElephantElephantFormationTest.java @@ -3,19 +3,19 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.piece.PieceType; -import janggi.domain.setup.RightElephantSetupPolicy; +import janggi.domain.setup.RightElephantElephantFormation; import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class RightElephantSetupPolicyTest { +class RightElephantElephantFormationTest { @Test @DisplayName("오른상 차림 테스트") void setUp() { - RightElephantSetupPolicy policy = new RightElephantSetupPolicy(); + RightElephantElephantFormation policy = new RightElephantElephantFormation(); Map expected = new LinkedHashMap<>(SetupPolicyTestFixture.상_마를_제외한_기물_배치_정보_제공()); expected.put(Position.valueOf(1, 2), PieceType.HORSE); From 82f1e1e06e9f09555e9d54522fde7f478213d85e Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 00:50:39 +0900 Subject: [PATCH 065/128] =?UTF-8?q?refactor:=20Direction=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=20=EC=83=81=EC=88=98=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/movement/Direction.java | 51 +++---------------- src/main/java/janggi/domain/piece/Cannon.java | 8 +-- .../java/janggi/domain/piece/Chariot.java | 8 +-- .../java/janggi/domain/piece/Elephant.java | 50 +++++++++--------- .../java/janggi/domain/piece/General.java | 16 +++--- src/main/java/janggi/domain/piece/Guard.java | 16 +++--- src/main/java/janggi/domain/piece/Horse.java | 34 ++++++------- .../java/janggi/domain/piece/Soldier.java | 14 ++--- .../java/janggi/domain/DirectionTest.java | 46 ----------------- .../janggi/domain/movement/MovementTest.java | 22 ++++---- .../domain/movement/RuleOfCannonTest.java | 2 +- .../domain/movement/RuleWithNoTracesTest.java | 4 +- .../domain/movement/RuleWithTracesTest.java | 2 +- 13 files changed, 96 insertions(+), 177 deletions(-) delete mode 100644 src/test/java/janggi/domain/DirectionTest.java diff --git a/src/main/java/janggi/domain/movement/Direction.java b/src/main/java/janggi/domain/movement/Direction.java index 5a95389635..16d1e61d11 100644 --- a/src/main/java/janggi/domain/movement/Direction.java +++ b/src/main/java/janggi/domain/movement/Direction.java @@ -1,23 +1,15 @@ package janggi.domain.movement; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.stream.IntStream; - public final class Direction { - private static final int MINIMUM_ROW_DIRECTION = -1; - private static final int MAXIMUM_ROW_DIRECTION = 1; - private static final int MINIMUM_COLUMN_DIRECTION = -1; - private static final int MAXIMUM_COLUMN_DIRECTION = 1; - private static final Map> CACHE; - - static { - CACHE = new LinkedHashMap<>(); - IntStream.range(MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION + 1) - .forEach(rowDirection -> CACHE.put(rowDirection, new LinkedHashMap<>())); - } - + public static final Direction UP = new Direction(-1, 0); + public static final Direction DOWN = new Direction(1, 0); + public static final Direction LEFT = new Direction(0, -1); + public static final Direction RIGHT = new Direction(0, 1); + public static final Direction UP_RIGHT = new Direction(-1, 1); + public static final Direction UP_LEFT = new Direction(-1, -1); + public static final Direction DOWN_RIGHT = new Direction(1, 1); + public static final Direction DOWN_LEFT = new Direction(1, -1); private final int rowDirection; private final int columnDirection; @@ -26,32 +18,6 @@ private Direction(final int rowDirection, final int columnDirection) { this.columnDirection = columnDirection; } - public static Direction valueOf(final int rowDirection, final int columnDirection) { - validateRowDirectionRange(rowDirection); - validateColumnDirectionRange(columnDirection); - final Map secondaryMap = CACHE.get(rowDirection); - if (!secondaryMap.containsKey(columnDirection)) { - secondaryMap.put(columnDirection, new Direction(rowDirection, columnDirection)); - } - - return secondaryMap.get(columnDirection); - } - - private static void validateRowDirectionRange(final int rowDirection) { - if (rowDirection < MINIMUM_ROW_DIRECTION || rowDirection > MAXIMUM_ROW_DIRECTION) { - throw new IllegalArgumentException(String.format( - "행 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_ROW_DIRECTION, MAXIMUM_ROW_DIRECTION)); - } - } - - private static void validateColumnDirectionRange(final int columnDirection) { - if (columnDirection < MINIMUM_COLUMN_DIRECTION - || columnDirection > MAXIMUM_COLUMN_DIRECTION) { - throw new IllegalArgumentException(String.format( - "열 방향 값은 %d ~ %d 사이의 정수 값이어야 합니다.", MINIMUM_COLUMN_DIRECTION, MAXIMUM_COLUMN_DIRECTION)); - } - } - public int getRowDirection() { return rowDirection; } @@ -59,5 +25,4 @@ public int getRowDirection() { public int getColumnDirection() { return columnDirection; } - } diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 69bf5896cf..cd0004e3a3 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -16,10 +16,10 @@ public class Cannon implements Piece { static { final List rules = List.of( - new RuleOfCannon(Direction.valueOf(1, 0)), - new RuleOfCannon(Direction.valueOf(-1, 0)), - new RuleOfCannon(Direction.valueOf(0, 1)), - new RuleOfCannon(Direction.valueOf(0, -1))); + new RuleOfCannon(Direction.UP), + new RuleOfCannon(Direction.DOWN), + new RuleOfCannon(Direction.RIGHT), + new RuleOfCannon(Direction.LEFT)); PIECE_ACTION = new PieceAction(rules); } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index b8c66739ab..cd39ca2cbe 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -20,10 +20,10 @@ public class Chariot implements Piece { static { final List rules = List.of( - new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.valueOf(1, 0)))), - new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.valueOf(-1, 0)))), - new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.valueOf(0, 1)))), - new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.valueOf(0, -1))))); + new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.UP))), + new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.DOWN))), + new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.RIGHT))), + new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.LEFT)))); PIECE_ACTION = new PieceAction(rules); } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index ae45fcac90..5eeeca25df 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -18,38 +18,38 @@ public class Elephant implements Piece { static { final List rules = List.of( new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(1, Direction.valueOf(-1, 1)), - new Movement(1, Direction.valueOf(-1, 1)))), + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(1, Direction.valueOf(1, 1)), - new Movement(1, Direction.valueOf(1, 1)))), + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.DOWN_RIGHT), + new Movement(1, Direction.DOWN_RIGHT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(-1, 0)), - new Movement(1, Direction.valueOf(-1, 1)), - new Movement(1, Direction.valueOf(-1, 1)))), + new Movement(1, Direction.UP), + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(-1, 0)), - new Movement(1, Direction.valueOf(-1, -1)), - new Movement(1, Direction.valueOf(-1, -1)))), + new Movement(1, Direction.UP), + new Movement(1, Direction.UP_LEFT), + new Movement(1, Direction.UP_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, -1)), - new Movement(1, Direction.valueOf(-1, -1)), - new Movement(1, Direction.valueOf(-1, -1)))), + new Movement(1, Direction.LEFT), + new Movement(1, Direction.UP_LEFT), + new Movement(1, Direction.UP_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, -1)), - new Movement(1, Direction.valueOf(1, -1)), - new Movement(1, Direction.valueOf(1, -1)))), + new Movement(1, Direction.LEFT), + new Movement(1, Direction.DOWN_LEFT), + new Movement(1, Direction.DOWN_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(1, 0)), - new Movement(1, Direction.valueOf(1, -1)), - new Movement(1, Direction.valueOf(1, -1)))), + new Movement(1, Direction.DOWN), + new Movement(1, Direction.DOWN_LEFT), + new Movement(1, Direction.DOWN_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(1, 0)), - new Movement(1, Direction.valueOf(1, 1)), - new Movement(1, Direction.valueOf(1, 1))) - )); + new Movement(1, Direction.DOWN), + new Movement(1, Direction.DOWN_RIGHT), + new Movement(1, Direction.DOWN_RIGHT))) + ); PIECE_ACTION = new PieceAction(rules); } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 97b76ceb93..8f7d23dfed 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -17,14 +17,14 @@ public class General implements Piece { static { final List rules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 0)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 0)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 1))))); + new RuleWithTraces(List.of(new Movement(1, Direction.UP_LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.UP))), + new RuleWithTraces(List.of(new Movement(1, Direction.UP_RIGHT))), + new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_RIGHT)))); PIECE_ACTION = new PieceAction(rules); } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 702cdf9da8..18c6fa5c8c 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -17,14 +17,14 @@ public class Guard implements Piece { static { final List rules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 0)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 0)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 1))))); + new RuleWithTraces(List.of(new Movement(1, Direction.UP_LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.UP))), + new RuleWithTraces(List.of(new Movement(1, Direction.UP_RIGHT))), + new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_RIGHT)))); PIECE_ACTION = new PieceAction(rules); } private final TeamType teamType; diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index d8f92aeb83..7b2ff1dcc7 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -20,30 +20,30 @@ public class Horse implements Piece { static { final List rules = List.of( new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(1, Direction.valueOf(-1, 1)))), + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.UP_RIGHT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(1, Direction.valueOf(1, 1)))), + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.DOWN_RIGHT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(-1, 0)), - new Movement(1, Direction.valueOf(-1, 1)))), + new Movement(1, Direction.UP), + new Movement(1, Direction.UP_RIGHT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(-1, 0)), - new Movement(1, Direction.valueOf(-1, -1)))), + new Movement(1, Direction.UP), + new Movement(1, Direction.UP_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, -1)), - new Movement(1, Direction.valueOf(-1, -1)))), + new Movement(1, Direction.LEFT), + new Movement(1, Direction.UP_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(0, -1)), - new Movement(1, Direction.valueOf(1, -1)))), + new Movement(1, Direction.LEFT), + new Movement(1, Direction.DOWN_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(1, 0)), - new Movement(1, Direction.valueOf(1, -1)))), + new Movement(1, Direction.DOWN), + new Movement(1, Direction.DOWN_LEFT))), new RuleWithNoTraces(List.of( - new Movement(1, Direction.valueOf(1, 0)), - new Movement(1, Direction.valueOf(1, 1))) - )); + new Movement(1, Direction.DOWN), + new Movement(1, Direction.DOWN_RIGHT))) + ); PIECE_ACTION = new PieceAction(rules); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index eeb4b44634..34c560095d 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -18,13 +18,13 @@ public class Soldier implements Piece { static { final List redRules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(1, 0))))); + new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), + new RuleWithTraces(List.of(new Movement(1, Direction.DOWN)))); final List blueRules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, -1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(0, 1)))), - new RuleWithTraces(List.of(new Movement(1, Direction.valueOf(-1, 0))))); + new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), + new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), + new RuleWithTraces(List.of(new Movement(1, Direction.UP)))); RED_PIECE_ACTION = new PieceAction(redRules); BLUE_PIECE_ACTION = new PieceAction(blueRules); } @@ -61,6 +61,6 @@ public List calculateMovablePositions(Position from, BoardMediator boa @Override public boolean canKill(final Piece target) { return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( - teamType); + teamType); } } diff --git a/src/test/java/janggi/domain/DirectionTest.java b/src/test/java/janggi/domain/DirectionTest.java deleted file mode 100644 index 723c1f96af..0000000000 --- a/src/test/java/janggi/domain/DirectionTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package janggi.domain; - -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.junit.jupiter.api.Assertions.*; - -import janggi.domain.movement.Direction; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -class DirectionTest { - - @Nested - @DisplayName("생성 테스트") - class Constructor { - - @Test - @DisplayName("정상 테스트") - void success() { - int row = 1; - int column = 1; - - assertDoesNotThrow(() -> Direction.valueOf(row, column)); - } - - @Test - @DisplayName("행 방향 값이 범위를 벗어난 경우") - void failure_1() { - int wrongRow = 2; - int column = 1; - - assertThatIllegalArgumentException() - .isThrownBy(() -> Direction.valueOf(wrongRow, column)); - } - - @Test - @DisplayName("열 방향 값이 범위를 벗어난 경우") - void failure_2() { - int wrongRow = 1; - int column = 2; - - assertThatIllegalArgumentException() - .isThrownBy(() -> Direction.valueOf(wrongRow, column)); - } - } -} \ No newline at end of file diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 373ec1a028..5cfa29598e 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -42,7 +42,7 @@ void success_1() { positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = true; @@ -57,7 +57,7 @@ void success_2() { positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.RED)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = false; @@ -71,7 +71,7 @@ void success_2() { void success_3() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = true; @@ -102,7 +102,7 @@ void setUp() { void success_1() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = false; @@ -117,7 +117,7 @@ void success_2() { positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = true; @@ -146,7 +146,7 @@ void success_1() { boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 5); @@ -164,7 +164,7 @@ void success_2() { boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 6); @@ -181,7 +181,7 @@ void success_3() { boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 7); @@ -213,7 +213,7 @@ void success_1() { boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); @@ -231,7 +231,7 @@ void success_2() { boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6)); @@ -249,7 +249,7 @@ void success_3() { boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(5, 3); int maxDistance = 4; - Direction direction = Direction.valueOf(0, 1); + Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6), Position.valueOf(5, 7)); diff --git a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java b/src/test/java/janggi/domain/movement/RuleOfCannonTest.java index b1fedb0b0c..4623c2d5b9 100644 --- a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java +++ b/src/test/java/janggi/domain/movement/RuleOfCannonTest.java @@ -33,7 +33,7 @@ void success() { positionPieceMap.put(Position.valueOf(6, 7), new Cannon(TeamType.RED)); BoardMediator boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(6, 7); - Rule ruleOfCannon = new RuleOfCannon(Direction.valueOf(0, -1)); + Rule ruleOfCannon = new RuleOfCannon(Direction.LEFT); List expected = List.of(Position.valueOf(6, 3)); List actual = ruleOfCannon.execute(from, boardMediator); diff --git a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java index b8603dc8b1..b1206d14c9 100644 --- a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java @@ -24,8 +24,8 @@ public void execute() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); List movementOrder = List.of( - new Movement(1, Direction.valueOf(0, 1)), - new Movement(2, Direction.valueOf(-1, 1))); + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT)); Rule ruleWithNoTraces = new RuleWithNoTraces(movementOrder); List expected = List.of(Position.valueOf(3, 6)); diff --git a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java index 3a6ec968c0..3c38c26386 100644 --- a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java +++ b/src/test/java/janggi/domain/movement/RuleWithTracesTest.java @@ -29,7 +29,7 @@ public void execute() { Position.valueOf(8, 3), new Elephant(TeamType.BLUE)); Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); - Direction direction = Direction.valueOf(1, 0); + Direction direction = Direction.DOWN; Rule ruleWithTraces = new RuleWithTraces( List.of(new Movement(MAXIMUM_ROW, direction))); List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), From 2da81005c05f4d471e0c22b69854d5c5dae55e89 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 12:58:37 +0900 Subject: [PATCH 066/128] =?UTF-8?q?refactor:=20Rule=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4,=20=EA=B5=AC=ED=98=84=EC=B2=B4=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RuleWithTraces -> SlidingMoveRule - RuleWithNoTraces -> StepMoveRule - RuleOfCannon -> CannonMoveRule --- ...{RuleOfCannon.java => CannonMoveRule.java} | 4 +- .../movement/{Rule.java => MoveRule.java} | 2 +- ...leWithTraces.java => SlidingMoveRule.java} | 4 +- ...uleWithNoTraces.java => StepMoveRule.java} | 4 +- src/main/java/janggi/domain/piece/Cannon.java | 16 ++--- .../java/janggi/domain/piece/Chariot.java | 16 ++--- .../java/janggi/domain/piece/Elephant.java | 26 ++++---- .../java/janggi/domain/piece/General.java | 24 +++---- src/main/java/janggi/domain/piece/Guard.java | 25 +++---- src/main/java/janggi/domain/piece/Horse.java | 66 +++++++++---------- .../java/janggi/domain/piece/PieceAction.java | 10 +-- .../java/janggi/domain/piece/Soldier.java | 24 +++---- ...annonTest.java => CannonMoveRuleTest.java} | 6 +- ...acesTest.java => SlidingMoveRuleTest.java} | 6 +- ...oTracesTest.java => StepMoveRuleTest.java} | 6 +- 15 files changed, 120 insertions(+), 119 deletions(-) rename src/main/java/janggi/domain/movement/{RuleOfCannon.java => CannonMoveRule.java} (92%) rename src/main/java/janggi/domain/movement/{Rule.java => MoveRule.java} (87%) rename src/main/java/janggi/domain/movement/{RuleWithTraces.java => SlidingMoveRule.java} (92%) rename src/main/java/janggi/domain/movement/{RuleWithNoTraces.java => StepMoveRule.java} (92%) rename src/test/java/janggi/domain/movement/{RuleOfCannonTest.java => CannonMoveRuleTest.java} (88%) rename src/test/java/janggi/domain/movement/{RuleWithTracesTest.java => SlidingMoveRuleTest.java} (87%) rename src/test/java/janggi/domain/movement/{RuleWithNoTracesTest.java => StepMoveRuleTest.java} (84%) diff --git a/src/main/java/janggi/domain/movement/RuleOfCannon.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java similarity index 92% rename from src/main/java/janggi/domain/movement/RuleOfCannon.java rename to src/main/java/janggi/domain/movement/CannonMoveRule.java index 1fe24073c7..4941d7533c 100644 --- a/src/main/java/janggi/domain/movement/RuleOfCannon.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -9,11 +9,11 @@ import java.util.ArrayList; import java.util.List; -public class RuleOfCannon implements Rule { +public class CannonMoveRule implements MoveRule { private final List movementOrder; - public RuleOfCannon(final Direction direction) { + public CannonMoveRule(final Direction direction) { this.movementOrder = generateMovementOrder(direction); } diff --git a/src/main/java/janggi/domain/movement/Rule.java b/src/main/java/janggi/domain/movement/MoveRule.java similarity index 87% rename from src/main/java/janggi/domain/movement/Rule.java rename to src/main/java/janggi/domain/movement/MoveRule.java index f1a9646639..a1209e12cf 100644 --- a/src/main/java/janggi/domain/movement/Rule.java +++ b/src/main/java/janggi/domain/movement/MoveRule.java @@ -4,6 +4,6 @@ import janggi.domain.board.BoardMediator; import java.util.List; -public interface Rule { +public interface MoveRule { List execute(Position from, BoardMediator boardMediator); } diff --git a/src/main/java/janggi/domain/movement/RuleWithTraces.java b/src/main/java/janggi/domain/movement/SlidingMoveRule.java similarity index 92% rename from src/main/java/janggi/domain/movement/RuleWithTraces.java rename to src/main/java/janggi/domain/movement/SlidingMoveRule.java index fac0610de8..334e449033 100644 --- a/src/main/java/janggi/domain/movement/RuleWithTraces.java +++ b/src/main/java/janggi/domain/movement/SlidingMoveRule.java @@ -6,11 +6,11 @@ import java.util.ArrayList; import java.util.List; -public class RuleWithTraces implements Rule { +public class SlidingMoveRule implements MoveRule { private final List movementOrder; - public RuleWithTraces(final List movementOrder) { + public SlidingMoveRule(final List movementOrder) { this.movementOrder = movementOrder; } diff --git a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java b/src/main/java/janggi/domain/movement/StepMoveRule.java similarity index 92% rename from src/main/java/janggi/domain/movement/RuleWithNoTraces.java rename to src/main/java/janggi/domain/movement/StepMoveRule.java index fd98d9b564..50599a42a0 100644 --- a/src/main/java/janggi/domain/movement/RuleWithNoTraces.java +++ b/src/main/java/janggi/domain/movement/StepMoveRule.java @@ -5,11 +5,11 @@ import janggi.domain.piece.Piece; import java.util.List; -public class RuleWithNoTraces implements Rule { +public class StepMoveRule implements MoveRule { private final List movementOrder; - public RuleWithNoTraces(final List movementOrder) { + public StepMoveRule(final List movementOrder) { this.movementOrder = movementOrder; } diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index cd0004e3a3..b5f6ce4556 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -2,9 +2,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.movement.CannonMoveRule; import janggi.domain.movement.Direction; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleOfCannon; +import janggi.domain.movement.MoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -15,12 +15,12 @@ public class Cannon implements Piece { private static final List UNCATCHABLE_PIECE_TYPES = List.of(PieceType.CANNON); static { - final List rules = List.of( - new RuleOfCannon(Direction.UP), - new RuleOfCannon(Direction.DOWN), - new RuleOfCannon(Direction.RIGHT), - new RuleOfCannon(Direction.LEFT)); - PIECE_ACTION = new PieceAction(rules); + final List movementStrategies = List.of( + new CannonMoveRule(Direction.UP), + new CannonMoveRule(Direction.DOWN), + new CannonMoveRule(Direction.RIGHT), + new CannonMoveRule(Direction.LEFT)); + PIECE_ACTION = new PieceAction(movementStrategies); } private final TeamType teamType; diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index cd39ca2cbe..d340eaf393 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -6,9 +6,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; +import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleWithTraces; +import janggi.domain.movement.SlidingMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -19,12 +19,12 @@ public class Chariot implements Piece { private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { - final List rules = List.of( - new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.UP))), - new RuleWithTraces(List.of(new Movement(MAXIMUM_ROW, Direction.DOWN))), - new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.RIGHT))), - new RuleWithTraces(List.of(new Movement(MAXIMUM_COLUMN, Direction.LEFT)))); - PIECE_ACTION = new PieceAction(rules); + final List movementStrategies = List.of( + new SlidingMoveRule(List.of(new Movement(MAXIMUM_ROW, Direction.UP))), + new SlidingMoveRule(List.of(new Movement(MAXIMUM_ROW, Direction.DOWN))), + new SlidingMoveRule(List.of(new Movement(MAXIMUM_COLUMN, Direction.RIGHT))), + new SlidingMoveRule(List.of(new Movement(MAXIMUM_COLUMN, Direction.LEFT)))); + PIECE_ACTION = new PieceAction(movementStrategies); } private final TeamType teamType; diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 5eeeca25df..9ca31ef6c5 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -3,9 +3,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; +import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleWithNoTraces; +import janggi.domain.movement.StepMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -16,42 +16,42 @@ public class Elephant implements Piece { private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { - final List rules = List.of( - new RuleWithNoTraces(List.of( + final List movementStrategies = List.of( + new StepMoveRule(List.of( new Movement(1, Direction.RIGHT), new Movement(1, Direction.UP_RIGHT), new Movement(1, Direction.UP_RIGHT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.RIGHT), new Movement(1, Direction.DOWN_RIGHT), new Movement(1, Direction.DOWN_RIGHT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.UP), new Movement(1, Direction.UP_RIGHT), new Movement(1, Direction.UP_RIGHT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.UP), new Movement(1, Direction.UP_LEFT), new Movement(1, Direction.UP_LEFT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.LEFT), new Movement(1, Direction.UP_LEFT), new Movement(1, Direction.UP_LEFT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.LEFT), new Movement(1, Direction.DOWN_LEFT), new Movement(1, Direction.DOWN_LEFT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.DOWN), new Movement(1, Direction.DOWN_LEFT), new Movement(1, Direction.DOWN_LEFT))), - new RuleWithNoTraces(List.of( + new StepMoveRule(List.of( new Movement(1, Direction.DOWN), new Movement(1, Direction.DOWN_RIGHT), new Movement(1, Direction.DOWN_RIGHT))) - ); + ); - PIECE_ACTION = new PieceAction(rules); + PIECE_ACTION = new PieceAction(movementStrategies); } private final TeamType teamType; diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 8f7d23dfed..29d96cae28 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -3,9 +3,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; +import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleWithTraces; +import janggi.domain.movement.SlidingMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -16,16 +16,16 @@ public class General implements Piece { private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { - final List rules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.UP_LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.UP))), - new RuleWithTraces(List.of(new Movement(1, Direction.UP_RIGHT))), - new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_RIGHT)))); - PIECE_ACTION = new PieceAction(rules); + final List movementStrategies = List.of( + new SlidingMoveRule(List.of(new Movement(1, Direction.UP_LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.UP))), + new SlidingMoveRule(List.of(new Movement(1, Direction.UP_RIGHT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_RIGHT)))); + PIECE_ACTION = new PieceAction(movementStrategies); } private final TeamType teamType; diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 18c6fa5c8c..d34ddb1783 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -3,9 +3,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; +import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleWithTraces; +import janggi.domain.movement.SlidingMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -16,17 +16,18 @@ public class Guard implements Piece { private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { - final List rules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.UP_LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.UP))), - new RuleWithTraces(List.of(new Movement(1, Direction.UP_RIGHT))), - new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN_RIGHT)))); - PIECE_ACTION = new PieceAction(rules); + final List movementStrategies = List.of( + new SlidingMoveRule(List.of(new Movement(1, Direction.UP_LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.UP))), + new SlidingMoveRule(List.of(new Movement(1, Direction.UP_RIGHT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_RIGHT)))); + PIECE_ACTION = new PieceAction(movementStrategies); } + private final TeamType teamType; public Guard(final TeamType teamType) { diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 7b2ff1dcc7..68c033ed7f 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -3,9 +3,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; +import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleWithNoTraces; +import janggi.domain.movement.StepMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -15,39 +15,39 @@ public class Horse implements Piece { private static final PieceAction PIECE_ACTION; private static final List UNCATCHABLE_PIECE_TYPES = List.of(); - private final TeamType teamType; - static { - final List rules = List.of( - new RuleWithNoTraces(List.of( - new Movement(1, Direction.RIGHT), - new Movement(1, Direction.UP_RIGHT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.RIGHT), - new Movement(1, Direction.DOWN_RIGHT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.UP), - new Movement(1, Direction.UP_RIGHT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.UP), - new Movement(1, Direction.UP_LEFT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.LEFT), - new Movement(1, Direction.UP_LEFT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.LEFT), - new Movement(1, Direction.DOWN_LEFT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.DOWN), - new Movement(1, Direction.DOWN_LEFT))), - new RuleWithNoTraces(List.of( - new Movement(1, Direction.DOWN), - new Movement(1, Direction.DOWN_RIGHT))) - ); + final List movementStrategies = List.of( + new StepMoveRule(List.of( + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.UP_RIGHT))), + new StepMoveRule(List.of( + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.DOWN_RIGHT))), + new StepMoveRule(List.of( + new Movement(1, Direction.UP), + new Movement(1, Direction.UP_RIGHT))), + new StepMoveRule(List.of( + new Movement(1, Direction.UP), + new Movement(1, Direction.UP_LEFT))), + new StepMoveRule(List.of( + new Movement(1, Direction.LEFT), + new Movement(1, Direction.UP_LEFT))), + new StepMoveRule(List.of( + new Movement(1, Direction.LEFT), + new Movement(1, Direction.DOWN_LEFT))), + new StepMoveRule(List.of( + new Movement(1, Direction.DOWN), + new Movement(1, Direction.DOWN_LEFT))), + new StepMoveRule(List.of( + new Movement(1, Direction.DOWN), + new Movement(1, Direction.DOWN_RIGHT))) + ); - PIECE_ACTION = new PieceAction(rules); + PIECE_ACTION = new PieceAction(movementStrategies); } + private final TeamType teamType; + public Horse(final TeamType teamType) { this.teamType = teamType; } @@ -69,12 +69,12 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from,boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, boardMediator); } @Override public boolean canKill(final Piece target) { return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( - teamType); + teamType); } } diff --git a/src/main/java/janggi/domain/piece/PieceAction.java b/src/main/java/janggi/domain/piece/PieceAction.java index e0c3edd6dd..78a2ea6efe 100644 --- a/src/main/java/janggi/domain/piece/PieceAction.java +++ b/src/main/java/janggi/domain/piece/PieceAction.java @@ -2,19 +2,19 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; -import janggi.domain.movement.Rule; +import janggi.domain.movement.MoveRule; import java.util.Collection; import java.util.List; public class PieceAction { - private final List rules; + private final List movementStrategies; - public PieceAction(List rules) { - this.rules = List.copyOf(rules); + public PieceAction(List movementStrategies) { + this.movementStrategies = List.copyOf(movementStrategies); } public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return rules.stream() + return movementStrategies.stream() .map(rule -> rule.execute(from, boardMediator)) .flatMap(Collection::stream) .toList(); diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 34c560095d..072de26a6a 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -3,9 +3,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; +import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; -import janggi.domain.movement.Rule; -import janggi.domain.movement.RuleWithTraces; +import janggi.domain.movement.SlidingMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -17,16 +17,16 @@ public class Soldier implements Piece { private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { - final List redRules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), - new RuleWithTraces(List.of(new Movement(1, Direction.DOWN)))); - final List blueRules = List.of( - new RuleWithTraces(List.of(new Movement(1, Direction.LEFT))), - new RuleWithTraces(List.of(new Movement(1, Direction.RIGHT))), - new RuleWithTraces(List.of(new Movement(1, Direction.UP)))); - RED_PIECE_ACTION = new PieceAction(redRules); - BLUE_PIECE_ACTION = new PieceAction(blueRules); + final List redMovementStrategies = List.of( + new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN)))); + final List blueMovementStrategies = List.of( + new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), + new SlidingMoveRule(List.of(new Movement(1, Direction.UP)))); + RED_PIECE_ACTION = new PieceAction(redMovementStrategies); + BLUE_PIECE_ACTION = new PieceAction(blueMovementStrategies); } private final TeamType teamType; diff --git a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java similarity index 88% rename from src/test/java/janggi/domain/movement/RuleOfCannonTest.java rename to src/test/java/janggi/domain/movement/CannonMoveRuleTest.java index 4623c2d5b9..4baa8f5e54 100644 --- a/src/test/java/janggi/domain/movement/RuleOfCannonTest.java +++ b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java @@ -17,7 +17,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -public class RuleOfCannonTest { +public class CannonMoveRuleTest { @Nested @@ -33,10 +33,10 @@ void success() { positionPieceMap.put(Position.valueOf(6, 7), new Cannon(TeamType.RED)); BoardMediator boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); Position from = Position.valueOf(6, 7); - Rule ruleOfCannon = new RuleOfCannon(Direction.LEFT); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.LEFT); List expected = List.of(Position.valueOf(6, 3)); - List actual = ruleOfCannon.execute(from, boardMediator); + List actual = moveRuleOfCannon.execute(from, boardMediator); assertThat(actual).isEqualTo(expected); } diff --git a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java similarity index 87% rename from src/test/java/janggi/domain/movement/RuleWithTracesTest.java rename to src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java index 3c38c26386..a787962fa2 100644 --- a/src/test/java/janggi/domain/movement/RuleWithTracesTest.java +++ b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java @@ -16,7 +16,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -public class RuleWithTracesTest { +public class SlidingMoveRuleTest { Board board; BoardMediator boardMediator; @@ -30,12 +30,12 @@ public void execute() { Board board = new Board(positionPieceMap); BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.DOWN; - Rule ruleWithTraces = new RuleWithTraces( + MoveRule moveRuleWithTraces = new SlidingMoveRule( List.of(new Movement(MAXIMUM_ROW, direction))); List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), Position.valueOf(8, 3)); - List actual = ruleWithTraces.execute(Position.valueOf(5, 3), boardMediator); + List actual = moveRuleWithTraces.execute(Position.valueOf(5, 3), boardMediator); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java similarity index 84% rename from src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java rename to src/test/java/janggi/domain/movement/StepMoveRuleTest.java index b1206d14c9..508230efc2 100644 --- a/src/test/java/janggi/domain/movement/RuleWithNoTracesTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -public class RuleWithNoTracesTest { +public class StepMoveRuleTest { @Test @DisplayName("이동 가능한 목적지 계산 테스트") @@ -26,10 +26,10 @@ public void execute() { List movementOrder = List.of( new Movement(1, Direction.RIGHT), new Movement(2, Direction.UP_RIGHT)); - Rule ruleWithNoTraces = new RuleWithNoTraces(movementOrder); + MoveRule moveRuleWithNoTraces = new StepMoveRule(movementOrder); List expected = List.of(Position.valueOf(3, 6)); - List actual = ruleWithNoTraces.execute(Position.valueOf(5, 3), boardMediator); + List actual = moveRuleWithNoTraces.execute(Position.valueOf(5, 3), boardMediator); assertThat(actual).hasSameElementsAs(expected); } From 6358f66f42147e3f23a2c0c97efbf13b7b5b0c47 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 13:50:31 +0900 Subject: [PATCH 067/128] =?UTF-8?q?refactor:=20SlidingMoveRule=20=EB=8B=A8?= =?UTF-8?q?=EC=88=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 항상 1개의 Movement를 활용함 --- .../domain/movement/SlidingMoveRule.java | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/main/java/janggi/domain/movement/SlidingMoveRule.java b/src/main/java/janggi/domain/movement/SlidingMoveRule.java index 334e449033..2972dc455e 100644 --- a/src/main/java/janggi/domain/movement/SlidingMoveRule.java +++ b/src/main/java/janggi/domain/movement/SlidingMoveRule.java @@ -3,7 +3,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; -import java.util.ArrayList; import java.util.List; public class SlidingMoveRule implements MoveRule { @@ -16,22 +15,8 @@ public SlidingMoveRule(final List movementOrder) { @Override public List execute(Position from, final BoardMediator boardMediator) { - final List traces = new ArrayList<>(); final Piece piece = boardMediator.getPieceInPosition(from); - for (int index = 0; index < movementOrder.size() - 1; index++) { - final Movement movement = movementOrder.get(index); - traces.addAll(movement.calculateTraces(from, piece, boardMediator)); - final Position destination = movement.calculateDestination(from, piece, boardMediator); - traces.add(destination); - from = destination; - } - return findLastPosition(from, piece, boardMediator, traces); - } - - private List findLastPosition(final Position from, final Piece piece, final BoardMediator boardMediator, - final List traces) { - final Movement lastMovement = movementOrder.getLast(); - traces.addAll(lastMovement.calculateTraces(from, piece, boardMediator)); - return traces; + final Movement movement = movementOrder.getFirst(); + return movement.calculateTraces(from, piece, boardMediator); } } From f2e774e9aca277e5b7a2383949b2bb7e32164113 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 13:51:32 +0900 Subject: [PATCH 068/128] =?UTF-8?q?refactor:=20CannonMoveRule=20=EB=8B=A8?= =?UTF-8?q?=EC=88=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 동일한 Movement 2개 사용한 것을 단일 movement 재사용으로 변경 - 포다리 검증 메서드 분리 --- .../domain/movement/CannonMoveRule.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index 4941d7533c..a4a5c3418f 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -11,29 +11,26 @@ public class CannonMoveRule implements MoveRule { - private final List movementOrder; + private final Movement movement; public CannonMoveRule(final Direction direction) { - this.movementOrder = generateMovementOrder(direction); - } - - private List generateMovementOrder(final Direction direction) { - return List.of( - new Movement(MAXIMUM_ROW, direction), - new Movement(MAXIMUM_ROW, direction)); + this.movement = new Movement(MAXIMUM_ROW, direction); } @Override public List execute(Position from, final BoardMediator boardMediator) { - final Movement findBridgeMovement = movementOrder.getFirst(); - final Movement findTraceesMovement = movementOrder.getLast(); final Piece piece = boardMediator.getPieceInPosition(from); - from = findBridgeMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); - if (!boardMediator.existsInPosition(from) - || boardMediator.getPieceInPosition(from).getPieceType() == PieceType.CANNON) { + from = movement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); // 포다리 찾기 + if (isInvalidBridge(from, boardMediator)) { return List.of(); } - final List traces = new ArrayList<>(findTraceesMovement.calculateTraces(from, piece, boardMediator)); + final List traces = new ArrayList<>(movement.calculateTraces(from, piece, boardMediator)); return traces; } + + // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) + private boolean isInvalidBridge(final Position bridge, final BoardMediator boardMediator) { + return !boardMediator.existsInPosition(bridge) + || boardMediator.getPieceInPosition(bridge).getPieceType() == PieceType.CANNON; + } } From c98114ed762153a428f1006bbe6087cdc36dbd9f Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 14:21:40 +0900 Subject: [PATCH 069/128] =?UTF-8?q?refactor:=20BoardMediator=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - existsInPosition -> hasPieceAt --- src/main/java/janggi/domain/board/BoardMediator.java | 2 +- src/main/java/janggi/domain/board/BoardMediatorImpl.java | 2 +- src/main/java/janggi/domain/movement/CannonMoveRule.java | 2 +- src/main/java/janggi/domain/movement/Movement.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java index 865c8bfcbb..0756effaae 100644 --- a/src/main/java/janggi/domain/board/BoardMediator.java +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -4,7 +4,7 @@ import janggi.domain.piece.Piece; public interface BoardMediator { - boolean existsInPosition(Position position); + boolean hasPieceAt(Position position); Piece getPieceInPosition(Position position); } diff --git a/src/main/java/janggi/domain/board/BoardMediatorImpl.java b/src/main/java/janggi/domain/board/BoardMediatorImpl.java index c064e3ea02..07fe18d470 100644 --- a/src/main/java/janggi/domain/board/BoardMediatorImpl.java +++ b/src/main/java/janggi/domain/board/BoardMediatorImpl.java @@ -12,7 +12,7 @@ public BoardMediatorImpl(final Board board) { } @Override - public boolean existsInPosition(final Position position) { + public boolean hasPieceAt(final Position position) { return !board.isBlank(position); } diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index a4a5c3418f..30dbe177e7 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -30,7 +30,7 @@ public List execute(Position from, final BoardMediator boardMediator) // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) private boolean isInvalidBridge(final Position bridge, final BoardMediator boardMediator) { - return !boardMediator.existsInPosition(bridge) + return !boardMediator.hasPieceAt(bridge) || boardMediator.getPieceInPosition(bridge).getPieceType() == PieceType.CANNON; } } diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 4a023ea072..08ee3255af 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -99,7 +99,7 @@ private Position calculateNextPosition(final Position from, final int distance) } private boolean hasPieceAt(final Position position, final BoardMediator boardMediator) { - return boardMediator.existsInPosition(position); + return boardMediator.hasPieceAt(position); } private Piece findPieceAt(final Position position, final BoardMediator boardMediator) { From 1e3d2ef7e483adb31edd9e0ebce04b3cf73e08b5 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 14:53:53 +0900 Subject: [PATCH 070/128] =?UTF-8?q?refactor:=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EC=9D=98=20UNCATCHABLE=5FPIECE=5FTY?= =?UTF-8?q?PES=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cannon에서 canKill의 조건에 cannon을 죽일 수 없는 것으로 변경 --- src/main/java/janggi/domain/piece/Cannon.java | 3 +-- src/main/java/janggi/domain/piece/Chariot.java | 3 +-- src/main/java/janggi/domain/piece/Elephant.java | 4 +--- src/main/java/janggi/domain/piece/General.java | 3 +-- src/main/java/janggi/domain/piece/Guard.java | 3 +-- src/main/java/janggi/domain/piece/Horse.java | 3 +-- src/main/java/janggi/domain/piece/Soldier.java | 4 +--- 7 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index b5f6ce4556..06e869a6ec 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -12,7 +12,6 @@ public class Cannon implements Piece { private static final PieceType PIECE_TYPE = PieceType.CANNON; private static final PieceAction PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(PieceType.CANNON); static { final List movementStrategies = List.of( @@ -51,6 +50,6 @@ public List calculateMovablePositions(final Position from, final Board @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); + return !PIECE_TYPE.equals(target.getPieceType()) && !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index d340eaf393..a3f7cb623d 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -16,7 +16,6 @@ public class Chariot implements Piece { private static final PieceType PIECE_TYPE = PieceType.CHARIOT; private static final PieceAction PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List movementStrategies = List.of( @@ -55,6 +54,6 @@ public List calculateMovablePositions(final Position from, final Board @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); + return !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 9ca31ef6c5..4451fcbc9c 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -13,7 +13,6 @@ public class Elephant implements Piece { private static final PieceType PIECE_TYPE = PieceType.ELEPHANT; private static final PieceAction PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List movementStrategies = List.of( @@ -83,7 +82,6 @@ public List calculateMovablePositions(final Position from, @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( - teamType); + return !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 29d96cae28..6fd3ba5753 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -13,7 +13,6 @@ public class General implements Piece { private static final PieceType PIECE_TYPE = PieceType.GENERAL; private static final PieceAction PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List movementStrategies = List.of( @@ -56,6 +55,6 @@ public List calculateMovablePositions(Position from, BoardMediator boa @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); + return !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index d34ddb1783..9c97c3fe9a 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -13,7 +13,6 @@ public class Guard implements Piece { private static final PieceType PIECE_TYPE = PieceType.GUARD; private static final PieceAction PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List movementStrategies = List.of( @@ -56,6 +55,6 @@ public List calculateMovablePositions(Position from, BoardMediator boa @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam(teamType); + return !target.belongsToTeam(teamType); } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 68c033ed7f..f97361b33b 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -13,7 +13,6 @@ public class Horse implements Piece { private static final PieceType PIECE_TYPE = PieceType.HORSE; private static final PieceAction PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List movementStrategies = List.of( @@ -74,7 +73,7 @@ public List calculateMovablePositions(Position from, BoardMediator boa @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( + return !target.belongsToTeam( teamType); } } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 072de26a6a..3f716300b9 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -14,7 +14,6 @@ public class Soldier implements Piece { private static final PieceType PIECE_TYPE = PieceType.SOLDIER; private static final PieceAction RED_PIECE_ACTION; private static final PieceAction BLUE_PIECE_ACTION; - private static final List UNCATCHABLE_PIECE_TYPES = List.of(); static { final List redMovementStrategies = List.of( @@ -60,7 +59,6 @@ public List calculateMovablePositions(Position from, BoardMediator boa @Override public boolean canKill(final Piece target) { - return !UNCATCHABLE_PIECE_TYPES.contains(target.getPieceType()) && !target.belongsToTeam( - teamType); + return !target.belongsToTeam(teamType); } } From 056b770406484a3b1cb87e914a35f4a2f0ef7a28 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sun, 29 Mar 2026 15:54:09 +0900 Subject: [PATCH 071/128] =?UTF-8?q?refactor:=20=20BoardMediatorImpl=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0,=20Board=EA=B0=80=20BoardMediator=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=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/janggi/domain/board/Board.java | 24 ++-- .../domain/board/BoardMediatorImpl.java | 23 ---- src/main/java/janggi/dto/BoardDto.java | 2 +- .../java/janggi/domain/BlueSoldierTest.java | 11 +- src/test/java/janggi/domain/BoardTest.java | 18 ++- src/test/java/janggi/domain/CannonTest.java | 11 +- src/test/java/janggi/domain/ChariotTest.java | 8 +- src/test/java/janggi/domain/ElephantTest.java | 11 +- src/test/java/janggi/domain/GeneralTest.java | 14 +-- src/test/java/janggi/domain/GuardTest.java | 11 +- src/test/java/janggi/domain/HorseTest.java | 14 +-- .../java/janggi/domain/RedSoldierTest.java | 11 +- .../domain/movement/CannonMoveRuleTest.java | 11 +- .../janggi/domain/movement/MovementTest.java | 109 ++++++++++-------- .../domain/movement/SlidingMoveRuleTest.java | 25 ++-- .../domain/movement/StepMoveRuleTest.java | 20 ++-- 16 files changed, 140 insertions(+), 183 deletions(-) delete mode 100644 src/main/java/janggi/domain/board/BoardMediatorImpl.java diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index d10ec872a6..0a42ef15e5 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -4,7 +4,7 @@ import janggi.domain.piece.Piece; import java.util.Map; -public class Board { +public class Board implements BoardMediator { private final Map positionPieceMap; @@ -12,16 +12,26 @@ public Board(final Map positionPieceMap) { this.positionPieceMap = positionPieceMap; } - public Map getPositionPieceMap() { - return positionPieceMap; + @Override + public boolean hasPieceAt(final Position position) { + return isNotBlank(position); } - public boolean isBlank(final Position position) { - return !positionPieceMap.containsKey(position); + @Override + public Piece getPieceInPosition(final Position position) { + return findPieceByPosition(position); } - public Piece findPieceByPosition(final Position position) { - if (isBlank(position)) { + public Map getPositionPieceMapForDTO() { + return Map.copyOf(positionPieceMap); + } + + private boolean isNotBlank(final Position position) { + return positionPieceMap.containsKey(position); + } + + private Piece findPieceByPosition(final Position position) { + if (!isNotBlank(position)) { throw new IllegalStateException("요청된 위치에는 기물이 존재하지 않습니다."); } return positionPieceMap.get(position); diff --git a/src/main/java/janggi/domain/board/BoardMediatorImpl.java b/src/main/java/janggi/domain/board/BoardMediatorImpl.java deleted file mode 100644 index 07fe18d470..0000000000 --- a/src/main/java/janggi/domain/board/BoardMediatorImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -package janggi.domain.board; - -import janggi.domain.Position; -import janggi.domain.piece.Piece; - -public class BoardMediatorImpl implements BoardMediator { - - private final Board board; - - public BoardMediatorImpl(final Board board) { - this.board = board; - } - - @Override - public boolean hasPieceAt(final Position position) { - return !board.isBlank(position); - } - - @Override - public Piece getPieceInPosition(final Position position) { - return board.findPieceByPosition(position); - } -} diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java index 6f05a8c871..0f90bfc9fe 100644 --- a/src/main/java/janggi/dto/BoardDto.java +++ b/src/main/java/janggi/dto/BoardDto.java @@ -47,7 +47,7 @@ public record BoardDto( public static BoardDto from(final Board board) { final List rowStatuses = new ArrayList<>(); - final Map positionPieceMap = board.getPositionPieceMap(); + final Map positionPieceMap = board.getPositionPieceMapForDTO(); for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { rowStatuses.add(composeRowStatus(row, positionPieceMap)); } diff --git a/src/test/java/janggi/domain/BlueSoldierTest.java b/src/test/java/janggi/domain/BlueSoldierTest.java index bca4796a80..2855628a3e 100644 --- a/src/test/java/janggi/domain/BlueSoldierTest.java +++ b/src/test/java/janggi/domain/BlueSoldierTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; @@ -53,10 +51,9 @@ void test1() { ); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = blueSoldier.calculateMovablePositions( - Position.valueOf(6, 4), boardMediator + Position.valueOf(6, 4), board ); assertThat(actual).hasSameElementsAs(expected); @@ -74,10 +71,9 @@ void test2() { ); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = blueSoldier.calculateMovablePositions( - Position.valueOf(6, 4), boardMediator + Position.valueOf(6, 4), board ); assertThat(actual).hasSameElementsAs(expected); @@ -92,10 +88,9 @@ void test3() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = blueSoldier.calculateMovablePositions( - Position.valueOf(1, 1), boardMediator + Position.valueOf(1, 1), board ); assertThat(actual).hasSameElementsAs(expected); diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 39e0d7821d..2ccce71206 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -24,9 +24,9 @@ class isBlank { void success_1() { Board board = new Board(new LinkedHashMap<>()); Position position = Position.valueOf(1, 1); - boolean expected = true; + boolean expected = false; - boolean actual = board.isBlank(position); + boolean actual = board.hasPieceAt(position); assertThat(actual).isEqualTo(expected); } @@ -35,12 +35,11 @@ void success_1() { @DisplayName("빈칸이 아닌 경우") void success_2() { Position position = Position.valueOf(1, 1); - Map positionPieceMap = Map.of( - position, new Cannon(TeamType.RED)); + Map positionPieceMap = Map.of(position, new Cannon(TeamType.RED)); Board board = new Board(positionPieceMap); - boolean expected = false; + boolean expected = true; - boolean actual = board.isBlank(position); + boolean actual = board.hasPieceAt(position); assertThat(actual).isEqualTo(expected); } @@ -55,11 +54,10 @@ class FindPieceByPosition { void success() { Position position = Position.valueOf(1, 1); Piece expected = new Cannon(TeamType.RED); - Map positionPieceMap = Map.of( - position, expected); + Map positionPieceMap = Map.of(position, expected); Board board = new Board(positionPieceMap); - Piece actual = board.findPieceByPosition(position); + Piece actual = board.getPieceInPosition(position); assertThat(actual).usingRecursiveComparison() .isEqualTo(expected); @@ -72,7 +70,7 @@ void failure() { Board board = new Board(new LinkedHashMap<>()); assertThatIllegalStateException() - .isThrownBy(() -> board.findPieceByPosition(position)); + .isThrownBy(() -> board.getPieceInPosition(position)); } } } diff --git a/src/test/java/janggi/domain/CannonTest.java b/src/test/java/janggi/domain/CannonTest.java index 05b64fbb73..afe8d0a9de 100644 --- a/src/test/java/janggi/domain/CannonTest.java +++ b/src/test/java/janggi/domain/CannonTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Cannon; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -46,7 +44,6 @@ void success_1() { Position.valueOf(6, 5), enemySoldier, Position.valueOf(7, 7), allySoldier); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List expected = List.of( Position.valueOf(6, 1), Position.valueOf(6, 2), @@ -57,7 +54,7 @@ void success_1() { Position.valueOf(10, 7)); List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - boardMediator); + board); assertThat(actual).hasSameElementsAs(expected); } @@ -71,14 +68,13 @@ void success_2() { Position.valueOf(6, 5), enemyCannon, Position.valueOf(9, 7), allyCannon); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List expected = List.of( Position.valueOf(1, 7), Position.valueOf(2, 7), Position.valueOf(3, 7)); List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - boardMediator); + board); assertThat(actual).hasSameElementsAs(expected); } @@ -91,11 +87,10 @@ void success_3() { Position.valueOf(6, 3), enemyCannon, Position.valueOf(6, 4), allySoldier); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List expected = List.of(); List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - boardMediator); + board); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/ChariotTest.java b/src/test/java/janggi/domain/ChariotTest.java index 95c486447e..a639b59329 100644 --- a/src/test/java/janggi/domain/ChariotTest.java +++ b/src/test/java/janggi/domain/ChariotTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Chariot; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -65,8 +63,7 @@ void test1() { Position.valueOf(6, 3), Position.valueOf(7, 3)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = chariot.calculateMovablePositions(Position.valueOf(5, 3), boardMediator); + List actual = chariot.calculateMovablePositions(Position.valueOf(5, 3), board); assertThat(actual).hasSameElementsAs(expected); } @@ -84,8 +81,7 @@ void test2() { Position.valueOf(5, 5), Position.valueOf(6, 3)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = chariot.calculateMovablePositions(Position.valueOf(5, 3), boardMediator); + List actual = chariot.calculateMovablePositions(Position.valueOf(5, 3), board); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/ElephantTest.java b/src/test/java/janggi/domain/ElephantTest.java index dc075dfa63..5e615c73af 100644 --- a/src/test/java/janggi/domain/ElephantTest.java +++ b/src/test/java/janggi/domain/ElephantTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Elephant; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -61,8 +59,7 @@ void test1() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = elephant.calculateMovablePositions(Position.valueOf(6, 4), boardMediator); + List actual = elephant.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -78,8 +75,7 @@ void test2() { Position.valueOf(9, 6)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = elephant.calculateMovablePositions(Position.valueOf(6, 4), boardMediator); + List actual = elephant.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -93,8 +89,7 @@ void test3() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = elephant.calculateMovablePositions(Position.valueOf(1, 1), boardMediator); + List actual = elephant.calculateMovablePositions(Position.valueOf(1, 1), board); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/GeneralTest.java b/src/test/java/janggi/domain/GeneralTest.java index d24f9818e5..4ef9e33068 100644 --- a/src/test/java/janggi/domain/GeneralTest.java +++ b/src/test/java/janggi/domain/GeneralTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.General; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -65,9 +63,7 @@ void test1() { Position.valueOf(7, 4), Position.valueOf(7, 5)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = general.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + List actual = general.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -83,9 +79,7 @@ void test2() { Position.valueOf(7, 4), Position.valueOf(7, 5)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = general.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + List actual = general.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -100,9 +94,7 @@ void test3() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = general.calculateMovablePositions(Position.valueOf(1, 1), - boardMediator); + List actual = general.calculateMovablePositions(Position.valueOf(1, 1), board); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/GuardTest.java b/src/test/java/janggi/domain/GuardTest.java index 453bbb40a5..c5c4e5cafb 100644 --- a/src/test/java/janggi/domain/GuardTest.java +++ b/src/test/java/janggi/domain/GuardTest.java @@ -4,7 +4,6 @@ import janggi.domain.board.Board; import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Guard; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -65,7 +64,7 @@ void test1() { Position.valueOf(7, 4), Position.valueOf(7, 5)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); + BoardMediator boardMediator = board; List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), boardMediator); @@ -83,9 +82,7 @@ void test2() { Position.valueOf(7, 4), Position.valueOf(7, 5)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + List actual = guard.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -100,9 +97,7 @@ void test3() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = guard.calculateMovablePositions(Position.valueOf(1, 1), - boardMediator); + List actual = guard.calculateMovablePositions(Position.valueOf(1, 1), board); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/HorseTest.java b/src/test/java/janggi/domain/HorseTest.java index 0c8422cb40..8544f9d7fe 100644 --- a/src/test/java/janggi/domain/HorseTest.java +++ b/src/test/java/janggi/domain/HorseTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Horse; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -59,9 +57,7 @@ void test1() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -78,9 +74,7 @@ void test2() { Position.valueOf(5, 2)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), - boardMediator); + List actual = horse.calculateMovablePositions(Position.valueOf(6, 4), board); assertThat(actual).hasSameElementsAs(expected); } @@ -94,9 +88,7 @@ void test3() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); - List actual = horse.calculateMovablePositions(Position.valueOf(1, 1), - boardMediator); + List actual = horse.calculateMovablePositions(Position.valueOf(1, 1), board); assertThat(actual).hasSameElementsAs(expected); } diff --git a/src/test/java/janggi/domain/RedSoldierTest.java b/src/test/java/janggi/domain/RedSoldierTest.java index 074f8e6949..d5d14a30aa 100644 --- a/src/test/java/janggi/domain/RedSoldierTest.java +++ b/src/test/java/janggi/domain/RedSoldierTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; @@ -53,10 +51,9 @@ void test1() { ); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = redSoldier.calculateMovablePositions( - Position.valueOf(6, 4), boardMediator + Position.valueOf(6, 4), board ); assertThat(actual).hasSameElementsAs(expected); @@ -74,10 +71,9 @@ void test2() { ); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = redSoldier.calculateMovablePositions( - Position.valueOf(6, 4), boardMediator + Position.valueOf(6, 4), board ); assertThat(actual).hasSameElementsAs(expected); @@ -92,10 +88,9 @@ void test3() { List expected = List.of(); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List actual = redSoldier.calculateMovablePositions( - Position.valueOf(10, 1), boardMediator + Position.valueOf(10, 1), board ); assertThat(actual).hasSameElementsAs(expected); diff --git a/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java index 4baa8f5e54..a6f9174b88 100644 --- a/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java @@ -4,8 +4,6 @@ import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Cannon; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -27,17 +25,20 @@ class Execute { @Test @DisplayName("이동 경로에 죽일 수 없는 기물이 있는 경우") void success() { + // given Map positionPieceMap = new LinkedHashMap<>(); positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); positionPieceMap.put(Position.valueOf(6, 4), new Soldier(TeamType.RED)); positionPieceMap.put(Position.valueOf(6, 7), new Cannon(TeamType.RED)); - BoardMediator boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Board board = new Board(positionPieceMap); Position from = Position.valueOf(6, 7); MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.LEFT); - List expected = List.of(Position.valueOf(6, 3)); - List actual = moveRuleOfCannon.execute(from, boardMediator); + // when + List actual = moveRuleOfCannon.execute(from, board); + // then + List expected = List.of(Position.valueOf(6, 3)); assertThat(actual).isEqualTo(expected); } } diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 5cfa29598e..c76ce49364 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -4,8 +4,6 @@ import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Chariot; import janggi.domain.piece.Piece; import janggi.domain.piece.Soldier; @@ -19,14 +17,13 @@ import org.junit.jupiter.api.Test; class MovementTest { - @Nested @DisplayName("잡기 여부 판정 테스트") class CanKill { - Position from; - Piece me; - Map positionPieceMap; + private static Position from; + private static Piece me; + private static Map positionPieceMap; @BeforeEach void setUp() { @@ -39,44 +36,50 @@ void setUp() { @Test @DisplayName("대상이 적군인 경우") void success_1() { + // given positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = true; - boolean actual = Movement.hasReachablePosition(me, from, boardMediator); + // when + boolean actual = Movement.hasReachablePosition(me, from, board); + // then assertThat(actual).isEqualTo(expected); } @Test @DisplayName("대상이 아군인 경우") void success_2() { + // given positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.RED)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = false; - boolean actual = Movement.hasReachablePosition(me, from, boardMediator); + // when + boolean actual = Movement.hasReachablePosition(me, from, board); + // then assertThat(actual).isEqualTo(expected); } @Test @DisplayName("대상이 없는 경우") void success_3() { + // given Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = true; - boolean actual = Movement.hasReachablePosition(me, from, boardMediator); + // when + boolean actual = Movement.hasReachablePosition(me, from, board); + // then assertThat(actual).isEqualTo(expected); } } @@ -85,9 +88,9 @@ void success_3() { @DisplayName("장애물 여부 판정 테스트") class IsBlocked { - Position from; - Piece me; - Map positionPieceMap; + private static Position from; + private static Piece me; + private static Map positionPieceMap; @BeforeEach void setUp() { @@ -100,29 +103,33 @@ void setUp() { @Test @DisplayName("기물이 없는 경우") void success_1() { + // given Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = false; - boolean actual = Movement.isBlocked(from, boardMediator); + // when + boolean actual = Movement.isBlocked(from, board); + // then assertThat(actual).isEqualTo(expected); } @Test @DisplayName("기물이 있는 경우") void success_2() { + // given positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.RIGHT; Movement Movement = new Movement(1, direction); boolean expected = true; - boolean actual = Movement.isBlocked(from, boardMediator); + // when + boolean actual = Movement.isBlocked(from, board); + // then assertThat(actual).isEqualTo(expected); } } @@ -131,64 +138,67 @@ void success_2() { @DisplayName("목적지 계산 테스트") class CalculateDestination { - Map positionPieceMap = new LinkedHashMap<>(); - BoardMediator boardMediator; + private static Map positionPieceMap; @BeforeEach void setUp() { + positionPieceMap = new LinkedHashMap<>(); positionPieceMap.put(Position.valueOf(5, 3), new Chariot(TeamType.RED)); } @Test @DisplayName("경로에 아군이 있는 경우") void success_1() { + // given positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.RED)); - boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 5); - Position actual = Movement.calculateDestination(from, - boardMediator.getPieceInPosition(from), - boardMediator); + // when + Position actual = Movement.calculateDestination(from, board.getPieceInPosition(from), board); + // then assertThat(actual).isEqualTo(expected); } @Test @DisplayName("경로에 적군이 있는 경우") void success_2() { + // given positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.BLUE)); - boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 6); - Position actual = Movement.calculateDestination(from, - boardMediator.getPieceInPosition(from), - boardMediator); + // when + Position actual = Movement.calculateDestination(from, board.getPieceInPosition(from), board); + // then assertThat(actual).isEqualTo(expected); } @Test @DisplayName("경로에 기물이 없는 경우") void success_3() { - boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + // given + Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); Position expected = Position.valueOf(5, 7); - Position actual = Movement.calculateDestination(from, - boardMediator.getPieceInPosition(from), - boardMediator); + // when + Position actual = Movement.calculateDestination(from, board.getPieceInPosition(from), board); + // then assertThat(actual).isEqualTo(expected); } @@ -198,37 +208,39 @@ void success_3() { @DisplayName("경로 자취 계산 테스트") class CalculateTraces { - Map positionPieceMap = new LinkedHashMap<>(); - BoardMediator boardMediator; + private static Map positionPieceMap; @BeforeEach void setUp() { + positionPieceMap = new LinkedHashMap<>(); positionPieceMap.put(Position.valueOf(5, 3), new Chariot(TeamType.RED)); } @Test @DisplayName("경로에 아군이 있는 경우") void success_1() { + // given positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.RED)); - boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); - List actual = Movement.calculateTraces(from, - boardMediator.getPieceInPosition(from), - boardMediator); + // when + List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), board); + // then assertThat(actual).hasSameElementsAs(expected); } @Test @DisplayName("경로에 적군이 있는 경우") void success_2() { + // given positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.BLUE)); - boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.RIGHT; @@ -236,17 +248,18 @@ void success_2() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6)); - List actual = Movement.calculateTraces(from, - boardMediator.getPieceInPosition(from), - boardMediator); + // when + List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), board); + // then assertThat(actual).hasSameElementsAs(expected); } @Test @DisplayName("경로에 기물이 없는 경우") void success_3() { - boardMediator = new BoardMediatorImpl(new Board(positionPieceMap)); + // given + Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); int maxDistance = 4; Direction direction = Direction.RIGHT; @@ -254,13 +267,11 @@ void success_3() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5), Position.valueOf(5, 6), Position.valueOf(5, 7)); - List actual = Movement.calculateTraces(from, - boardMediator.getPieceInPosition(from), - boardMediator); + // when + List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), board); + // then assertThat(actual).hasSameElementsAs(expected); } - } - } \ No newline at end of file diff --git a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java index a787962fa2..664078fa60 100644 --- a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java @@ -5,8 +5,6 @@ import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Chariot; import janggi.domain.piece.Elephant; import janggi.domain.piece.Piece; @@ -18,25 +16,30 @@ public class SlidingMoveRuleTest { - Board board; - BoardMediator boardMediator; - @Test @DisplayName("이동 가능한 자취 경로 계산 테스트") public void execute() { + // given Map positionPieceMap = Map.of( Position.valueOf(5, 3), new Chariot(TeamType.RED), - Position.valueOf(8, 3), new Elephant(TeamType.BLUE)); + Position.valueOf(8, 3), new Elephant(TeamType.BLUE) + ); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); Direction direction = Direction.DOWN; MoveRule moveRuleWithTraces = new SlidingMoveRule( - List.of(new Movement(MAXIMUM_ROW, direction))); - List expected = List.of(Position.valueOf(6, 3), Position.valueOf(7, 3), - Position.valueOf(8, 3)); + List.of(new Movement(MAXIMUM_ROW, direction)) + ); + Position from = Position.valueOf(5, 3); - List actual = moveRuleWithTraces.execute(Position.valueOf(5, 3), boardMediator); + // when + List actual = moveRuleWithTraces.execute(from, board); + // then + List expected = List.of( + Position.valueOf(6, 3), + Position.valueOf(7, 3), + Position.valueOf(8, 3) + ); assertThat(actual).hasSameElementsAs(expected); } } diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index 508230efc2..bee4f8b705 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -4,8 +4,6 @@ import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.board.BoardMediator; -import janggi.domain.board.BoardMediatorImpl; import janggi.domain.piece.Elephant; import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; @@ -18,20 +16,24 @@ public class StepMoveRuleTest { @Test @DisplayName("이동 가능한 목적지 계산 테스트") - public void execute() { + void execute() { + // given Map positionPieceMap = Map.of( - Position.valueOf(5, 3), new Elephant(TeamType.RED)); + Position.valueOf(5, 3), new Elephant(TeamType.RED) + ); Board board = new Board(positionPieceMap); - BoardMediator boardMediator = new BoardMediatorImpl(board); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT)); + new Movement(2, Direction.UP_RIGHT) + ); MoveRule moveRuleWithNoTraces = new StepMoveRule(movementOrder); - List expected = List.of(Position.valueOf(3, 6)); + Position from = Position.valueOf(5, 3); - List actual = moveRuleWithNoTraces.execute(Position.valueOf(5, 3), boardMediator); + // when + List actual = moveRuleWithNoTraces.execute(from, board); + // then + List expected = List.of(Position.valueOf(3, 6)); assertThat(actual).hasSameElementsAs(expected); } - } From f4a58135c19a37c56cc6638437df3ab38aa88064 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 16:02:44 +0900 Subject: [PATCH 072/128] =?UTF-8?q?feat:=20=EB=B3=B4=EB=93=9C=ED=8C=90=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=EC=97=90=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=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/janggi/dto/BoardDto.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java index 0f90bfc9fe..204f6eb959 100644 --- a/src/main/java/janggi/dto/BoardDto.java +++ b/src/main/java/janggi/dto/BoardDto.java @@ -22,6 +22,7 @@ public record BoardDto( private static final Map> CHINESE_MAP; private static final String EMPTY_SPACE = "*"; private static final String DELIMITER = " "; + private static final String[] INDEX_LABELS = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; static { CHINESE_MAP = Map.of( @@ -48,16 +49,29 @@ public record BoardDto( public static BoardDto from(final Board board) { final List rowStatuses = new ArrayList<>(); final Map positionPieceMap = board.getPositionPieceMapForDTO(); + rowStatuses.add(generateColumnIndex()); for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { rowStatuses.add(composeRowStatus(row, positionPieceMap)); } - return new BoardDto(rowStatuses); } + private static String generateColumnIndex() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(DELIMITER); + stringBuilder.append(DELIMITER); + for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { + stringBuilder.append(DELIMITER); + stringBuilder.append(INDEX_LABELS[column - 1]); + } + return stringBuilder.toString(); + } + private static String composeRowStatus(final int row, final Map positionPieceMap) { final StringBuilder stringBuilder = new StringBuilder(); Position current; + stringBuilder.append(DELIMITER); + stringBuilder.append(INDEX_LABELS[row - 1]); for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { current = Position.valueOf(row, column); stringBuilder.append(DELIMITER); From b7f334fb6438db4ef5354695b8f9f6da8d398de1 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 16:20:57 +0900 Subject: [PATCH 073/128] =?UTF-8?q?docs:=20readme=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EB=A3=A8=ED=94=84=20=EB=A1=9C=EC=A7=81=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=AA=A9=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 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 41f0c24f1f..ea123ed478 100644 --- a/README.md +++ b/README.md @@ -37,4 +37,11 @@ - 사 (士): 모든 방향으로 1칸 이동 가능 - 장 (將): 모든 방향으로 1칸 이동 가능 - 포 (砲): 반드시 하나를 넘어 전후좌우로 이동이 가능하고 포는 서로 넘거나 잡을 수 없다. - - 졸 (卒): 앞, 왼쪽, 오른쪽 1칸씩 이동 가능 \ No newline at end of file + - 졸 (卒): 앞, 왼쪽, 오른쪽 1칸씩 이동 가능 + +- 게임 루프 로직 + - 처음엔 한나라(Red Team)로 시작한다. + - 각 플레이어가 움직일 기물의 위치를 입력한다. + - 기물 이동 구현의 규칙과 같다. + - 한나라 -> 초나라 -> 한나라... 반복된다. + - 종료 조건은 어느 한 팀의 장 기물이 잡히면 게임은 종료된다. \ No newline at end of file From 6ad1979f1a4164a25a70a1bf25948422d73ead5c Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 16:22:37 +0900 Subject: [PATCH 074/128] =?UTF-8?q?feat:=20TurnManager=EB=A1=9C=20?= =?UTF-8?q?=EC=9E=A5=EA=B8=B0=EC=9D=98=20=ED=98=84=EC=9E=AC=20=ED=84=B4?= =?UTF-8?q?=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/team/TeamType.java | 7 +++++++ .../java/janggi/domain/team/TurnManager.java | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/janggi/domain/team/TurnManager.java diff --git a/src/main/java/janggi/domain/team/TeamType.java b/src/main/java/janggi/domain/team/TeamType.java index 9de33406ce..90d4099153 100644 --- a/src/main/java/janggi/domain/team/TeamType.java +++ b/src/main/java/janggi/domain/team/TeamType.java @@ -13,4 +13,11 @@ public enum TeamType { public String getName() { return name; } + + public TeamType nextTeamType() { + if (this == RED) { + return BLUE; + } + return RED; + } } diff --git a/src/main/java/janggi/domain/team/TurnManager.java b/src/main/java/janggi/domain/team/TurnManager.java new file mode 100644 index 0000000000..c024b11cef --- /dev/null +++ b/src/main/java/janggi/domain/team/TurnManager.java @@ -0,0 +1,17 @@ +package janggi.domain.team; + +public class TurnManager { + private final Team redTeam; + private final Team blueTeam; + private TeamType currentTurnTeamType; + + public TurnManager(Team redTeam, Team blueTeam) { + this.redTeam = redTeam; + this.blueTeam = blueTeam; + currentTurnTeamType = TeamType.RED; + } + + public void changeTurn() { + this.currentTurnTeamType = currentTurnTeamType.nextTeamType(); + } +} From 69f3958a2228b0ae4294ea5df7db0011437a40e4 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 17:54:58 +0900 Subject: [PATCH 075/128] =?UTF-8?q?feat:=20=EC=9D=B4=EB=8F=99=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=9C=20=EC=9C=84=EC=B9=98=EB=A5=BC=20=EC=B4=88?= =?UTF-8?q?=EB=A1=9D=20=EB=B0=B0=EA=B2=BD=EC=9C=BC=EB=A1=9C=20=EC=8B=9C?= =?UTF-8?q?=EC=9E=91=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/dto/BoardDto.java | 38 ++++++++++++++++++++- src/main/java/janggi/view/ConsoleColor.java | 4 +++ src/main/java/janggi/view/OutputView.java | 15 +++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java index 204f6eb959..868ef23e85 100644 --- a/src/main/java/janggi/dto/BoardDto.java +++ b/src/main/java/janggi/dto/BoardDto.java @@ -56,6 +56,16 @@ public static BoardDto from(final Board board) { return new BoardDto(rowStatuses); } + public static BoardDto from(final Board board, List movable) { + final List rowStatuses = new ArrayList<>(); + final Map positionPieceMap = board.getPositionPieceMapForDTO(); + rowStatuses.add(generateColumnIndex()); + for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { + rowStatuses.add(composeRowStatusWithMovable(row, positionPieceMap, movable)); + } + return new BoardDto(rowStatuses); + } + private static String generateColumnIndex() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(DELIMITER); @@ -81,6 +91,25 @@ private static String composeRowStatus(final int row, final Map return stringBuilder.toString(); } + private static String composeRowStatusWithMovable(final int row, final Map positionPieceMap, + List movable) { + final StringBuilder stringBuilder = new StringBuilder(); + Position current; + stringBuilder.append(DELIMITER); + stringBuilder.append(INDEX_LABELS[row - 1]); + for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { + current = Position.valueOf(row, column); + stringBuilder.append(DELIMITER); + if (movable.contains(current)) { + stringBuilder.append(getSpaceWithBackGround(current, positionPieceMap)); + continue; + } + stringBuilder.append(getSpace(current, positionPieceMap)); + } + + return stringBuilder.toString(); + } + private static String getSpace(final Position position, final Map positionPieceMap) { if (positionPieceMap.containsKey(position)) { final Piece piece = positionPieceMap.get(position); @@ -89,9 +118,16 @@ private static String getSpace(final Position position, final Map positionPieceMap) { + if (positionPieceMap.containsKey(position)) { + final Piece piece = positionPieceMap.get(position); + return ConsoleColor.getGreenBackground(getChineseOf(piece)); + } + return ConsoleColor.getGreenBackground(EMPTY_SPACE); + } + private static String getChineseOf(final Piece piece) { final Map secondaryMap = CHINESE_MAP.get(piece.getTeamType()); return secondaryMap.get(piece.getPieceType()); } - } diff --git a/src/main/java/janggi/view/ConsoleColor.java b/src/main/java/janggi/view/ConsoleColor.java index 1d989e314d..983c3551e5 100644 --- a/src/main/java/janggi/view/ConsoleColor.java +++ b/src/main/java/janggi/view/ConsoleColor.java @@ -4,6 +4,7 @@ public final class ConsoleColor { private static final String RED = "\u001B[31m"; private static final String BLUE = "\u001B[34m"; + private static final String GREEN_BACKGROUND = "\u001B[42m"; private static final String EXIT = "\u001B[0m"; private ConsoleColor() { @@ -17,4 +18,7 @@ public static String blue(final String string) { return BLUE + string + EXIT; } + public static String getGreenBackground(final String string) { + return GREEN_BACKGROUND + string + EXIT; + } } diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index ceaebe78b4..b1af2a9d96 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -27,10 +27,23 @@ public static void printErrorMessage(String message) { System.out.println(ERROR_PREFIX + message); } - public static void printBoard(final BoardDto boardDto) { + public static void printBoard(final BoardDto boardDto, String currentTeamType) { + System.out.println(currentTeamType + "의 차례입니다."); + printBoardWithMovable(boardDto); + } + + public static void printBoardWithMovable(BoardDto boardDto) { final List rowStatuses = boardDto.rowStatuses(); for (String rowStatus : rowStatuses) { System.out.println(rowStatus); } } + + public static void printInputFromPosition() { + System.out.println("움직이고 싶은 기물의 위치를 n,n 형태로 입력해주세요."); + } + + public static void printInputToPosition() { + System.out.println("이동하고 싶은 위치를 n,n 형태로 입력해주세요."); + } } From 0084104a08295c66ff80d7c9ab383dad2ee903ef Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 17:55:18 +0900 Subject: [PATCH 076/128] =?UTF-8?q?feat:=20=ED=84=B4=EC=A0=9C=20=EB=A3=A8?= =?UTF-8?q?=ED=94=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/controller/JanggiController.java | 49 ++++++++++++++++--- src/main/java/janggi/domain/board/Board.java | 4 ++ .../java/janggi/domain/team/TurnManager.java | 16 ++++-- src/main/java/janggi/view/InputView.java | 28 +++++++++++ 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 35ae0c7fa4..38a8e4f123 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -1,22 +1,43 @@ package janggi.controller; +import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; import janggi.domain.command.SetupCommand; +import janggi.domain.piece.Piece; import janggi.domain.setup.ElephantFormation; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import janggi.domain.team.Team; import janggi.domain.team.TeamType; +import janggi.domain.team.TurnManager; import janggi.dto.BoardDto; import janggi.utils.RetryExecutor; import janggi.view.InputView; import janggi.view.OutputView; +import java.util.List; public class JanggiController { public JanggiController() { } + public void run() { + Team redTeam = setupRedTeam(); + Team blueTeam = setupBlueTeam(); + Board board = BoardGenerator.generate(redTeam, blueTeam); + TurnManager turnManager = new TurnManager(); + while (true) { + OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); + Position from = inputFromPosition(board, turnManager); + Piece piece = board.getPieceInPosition(from); + List movable = piece.calculateMovablePositions(from, board); + OutputView.printBoardWithMovable(BoardDto.from(board, movable)); + Position to = inputToPosition(movable); + board.changeBoard(from, to); + turnManager.changeTurn(); + } + } + private Team setupRedTeam() { OutputView.printSetupGuide(TeamType.RED); final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); @@ -31,15 +52,29 @@ private Team setupBlueTeam() { return new BlueTeam(elephantFormation); } - public void run() { - Team redTeam = setupRedTeam(); - Team blueTeam = setupBlueTeam(); - Board board = BoardGenerator.generate(redTeam, blueTeam); - OutputView.printBoard(BoardDto.from(board)); - } - private SetupCommand readSetupCommand() { int inputCommand = InputView.readSetupCommand(); return SetupCommand.values()[inputCommand - 1]; } + + private Position inputFromPosition(Board board, TurnManager turnManager) { + while (true) { + OutputView.printInputFromPosition(); + Position from = InputView.readPosition(); + Piece piece = board.getPieceInPosition(from); + if (turnManager.checkFromTurn(piece)) { + return from; + } + } + } + + private Position inputToPosition(List movable) { + while (true) { + OutputView.printInputToPosition(); + Position from = InputView.readPosition(); + if (movable.contains(from)) { + return from; + } + } + } } diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 0a42ef15e5..96fce10d8a 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -12,6 +12,10 @@ public Board(final Map positionPieceMap) { this.positionPieceMap = positionPieceMap; } + public void changeBoard(final Position from, final Position to) { + positionPieceMap.put(to, positionPieceMap.remove(from)); + } + @Override public boolean hasPieceAt(final Position position) { return isNotBlank(position); diff --git a/src/main/java/janggi/domain/team/TurnManager.java b/src/main/java/janggi/domain/team/TurnManager.java index c024b11cef..c84bb1b3e3 100644 --- a/src/main/java/janggi/domain/team/TurnManager.java +++ b/src/main/java/janggi/domain/team/TurnManager.java @@ -1,17 +1,23 @@ package janggi.domain.team; +import janggi.domain.piece.Piece; + public class TurnManager { - private final Team redTeam; - private final Team blueTeam; private TeamType currentTurnTeamType; - public TurnManager(Team redTeam, Team blueTeam) { - this.redTeam = redTeam; - this.blueTeam = blueTeam; + public TurnManager() { currentTurnTeamType = TeamType.RED; } public void changeTurn() { this.currentTurnTeamType = currentTurnTeamType.nextTeamType(); } + + public boolean checkFromTurn(Piece piece) { + return piece.getTeamType() == currentTurnTeamType; + } + + public String currentTeamType() { + return currentTurnTeamType.getName(); + } } diff --git a/src/main/java/janggi/view/InputView.java b/src/main/java/janggi/view/InputView.java index 5ed047a2d0..d08dd8a90e 100644 --- a/src/main/java/janggi/view/InputView.java +++ b/src/main/java/janggi/view/InputView.java @@ -1,5 +1,11 @@ package janggi.view; +import static janggi.domain.Position.MAXIMUM_COLUMN; +import static janggi.domain.Position.MAXIMUM_ROW; +import static janggi.domain.Position.MINIMUM_COLUMN; +import static janggi.domain.Position.MINIMUM_ROW; + +import janggi.domain.Position; import janggi.utils.Parser; import janggi.view.reader.Console; @@ -19,4 +25,26 @@ public static int readSetupCommand() { throw new IllegalArgumentException( "명령 번호는 " + MIN_SETUP_COMMAND + "에서 " + MAX_SETUP_COMMAND + "까지의 정수 값이어야 합니다."); } + + public static Position readPosition() { + String input = Console.readLine(); + String[] parts = input.split(","); + int inputRow = Parser.parseInteger(parts[0].trim()); + validateRowRange(inputRow); + int inputColumn = Parser.parseInteger(parts[1].trim()); + validateColumnRange(inputColumn); + return Position.valueOf(inputRow, inputColumn); + } + + private static void validateRowRange(final int row) { + if (row < MINIMUM_ROW || row > MAXIMUM_ROW) { + throw new IllegalArgumentException("행 입력은 1~10을 입력해야 합니다."); + } + } + + private static void validateColumnRange(final int column) { + if (column < MINIMUM_COLUMN || column > MAXIMUM_COLUMN) { + throw new IllegalArgumentException("열 입력은 1~9을 입력해야 합니다."); + } + } } From 2d2ade89504019b828a6fd925e7bd88a73a78d1b Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 18:26:37 +0900 Subject: [PATCH 077/128] =?UTF-8?q?=20test:=20=EB=B3=B4=EB=93=9C=EC=97=90?= =?UTF-8?q?=20=EC=99=95=EC=9D=B4=202=EA=B0=9C=EC=9D=B8=EC=A7=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20=EB=8B=A8=EC=9C=84=20?= =?UTF-8?q?=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/janggi/domain/BoardTest.java | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 2ccce71206..bc6393236d 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -5,6 +5,7 @@ import janggi.domain.board.Board; import janggi.domain.piece.Cannon; +import janggi.domain.piece.General; import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; @@ -15,6 +16,38 @@ public class BoardTest { + @Test + @DisplayName("보드에 왕이 2개 경우") + void generalIsTwo() { + Map positionPieceMap = Map.of(); + Position position1 = Position.valueOf(9, 5); + Position position2 = Position.valueOf(2, 5); + positionPieceMap = Map.of( + position1, new General(TeamType.BLUE), + position2, new General(TeamType.RED)); + Board board = new Board(positionPieceMap); + boolean expected = true; + + boolean actual = board.hasTwoGeneral(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("보드에 왕이 2개 미만인 경우") + void generalIsOne() { + Map positionPieceMap = Map.of(); + Position position1 = Position.valueOf(9, 5); + positionPieceMap = Map.of( + position1, new General(TeamType.BLUE)); + Board board = new Board(positionPieceMap); + boolean expected = false; + + boolean actual = board.hasTwoGeneral(); + + assertThat(actual).isEqualTo(expected); + } + @Nested @DisplayName("빈칸 여부 테스트") class isBlank { From b4c4c9e7dd5f5a2348424d1c8c7b6aa8c09fd290 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 18:30:22 +0900 Subject: [PATCH 078/128] =?UTF-8?q?feat:=20=EC=99=95=EC=9D=B4=202=EA=B0=9C?= =?UTF-8?q?=20=EB=AF=B8=EB=A7=8C=EC=9D=B4=EB=A9=B4=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EB=A3=A8=ED=94=84=20=EC=A2=85=EB=A3=8C=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=A2=85=EB=A3=8C=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/controller/JanggiController.java | 2 +- src/main/java/janggi/domain/board/Board.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 38a8e4f123..a8d9ba3279 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -26,7 +26,7 @@ public void run() { Team blueTeam = setupBlueTeam(); Board board = BoardGenerator.generate(redTeam, blueTeam); TurnManager turnManager = new TurnManager(); - while (true) { + while (board.hasTwoGeneral()) { OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); Position from = inputFromPosition(board, turnManager); Piece piece = board.getPieceInPosition(from); diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 96fce10d8a..327e0136e1 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -2,6 +2,7 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import java.util.Map; public class Board implements BoardMediator { @@ -30,6 +31,14 @@ public Map getPositionPieceMapForDTO() { return Map.copyOf(positionPieceMap); } + public boolean hasTwoGeneral() { + long generalCount = positionPieceMap.values().stream() + .filter(piece -> piece.getPieceType() == PieceType.GENERAL) + .count(); + return generalCount == 2; + } + + private boolean isNotBlank(final Position position) { return positionPieceMap.containsKey(position); } From e3471483baa3fee148e1f638c2d5ed230fc77f9d Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 20:42:55 +0900 Subject: [PATCH 079/128] =?UTF-8?q?fix:=20=EB=B9=88=EC=B9=B8=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20IllIllegalArgumentException=EC=9C=BC=EB=A1=9C=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 --- src/main/java/janggi/domain/board/Board.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 327e0136e1..fca02fc264 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -45,7 +45,7 @@ private boolean isNotBlank(final Position position) { private Piece findPieceByPosition(final Position position) { if (!isNotBlank(position)) { - throw new IllegalStateException("요청된 위치에는 기물이 존재하지 않습니다."); + throw new IllegalArgumentException("요청된 위치에는 기물이 존재하지 않습니다."); } return positionPieceMap.get(position); } From b1adc9f3c1045d739e550b099199f4435c3565d2 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 20:44:57 +0900 Subject: [PATCH 080/128] =?UTF-8?q?feat:=20=EC=9D=B4=EB=8F=99=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=9C=20=EC=9C=84=EC=B9=98=EA=B0=80=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=AC=BC=EC=9D=84=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=ED=95=9C=20=EA=B2=BD=EC=9A=B0=20=EB=8B=A4=EC=8B=9C=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=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 - 입력에 모두 RetryExecutor.retry() 적용 --- .../janggi/controller/JanggiController.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index a8d9ba3279..caec3424ec 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -28,11 +28,11 @@ public void run() { TurnManager turnManager = new TurnManager(); while (board.hasTwoGeneral()) { OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); - Position from = inputFromPosition(board, turnManager); + Position from = findFromPosition(board, turnManager); Piece piece = board.getPieceInPosition(from); List movable = piece.calculateMovablePositions(from, board); OutputView.printBoardWithMovable(BoardDto.from(board, movable)); - Position to = inputToPosition(movable); + Position to = RetryExecutor.retry(() -> inputToPosition(movable)); board.changeBoard(from, to); turnManager.changeTurn(); } @@ -57,23 +57,45 @@ private SetupCommand readSetupCommand() { return SetupCommand.values()[inputCommand - 1]; } - private Position inputFromPosition(Board board, TurnManager turnManager) { + private Position findFromPosition(Board board, TurnManager turnManager) { while (true) { - OutputView.printInputFromPosition(); - Position from = InputView.readPosition(); + Position from = RetryExecutor.retry(() -> inputFromPosition(board, turnManager)); Piece piece = board.getPieceInPosition(from); - if (turnManager.checkFromTurn(piece)) { + List movable = piece.calculateMovablePositions(from, board); + if (!movable.isEmpty()) { return from; } + OutputView.printErrorMessage("이동 가능한 위치가 없습니다. 다른 기물을 선택하세요."); } } - private Position inputToPosition(List movable) { + private Position inputFromPosition(Board board, TurnManager turnManager) { while (true) { - OutputView.printInputToPosition(); - Position from = InputView.readPosition(); - if (movable.contains(from)) { + try { + OutputView.printInputFromPosition(); + Position from = InputView.readPosition(); + Piece piece = board.getPieceInPosition(from); + if (!turnManager.checkFromTurn(piece)) { + throw new IllegalArgumentException("자신의 기물을 선택하세요."); + } return from; + } catch (IllegalArgumentException e) { + OutputView.printErrorMessage(e.getMessage()); + } + } + } + + private Position inputToPosition(List movable) { + while (true) { + try { + OutputView.printInputToPosition(); + Position to = InputView.readPosition(); + if (!movable.contains(to)) { + throw new IllegalArgumentException("이동 불가능한 위치입니다."); + } + return to; + } catch (IllegalArgumentException e) { + OutputView.printErrorMessage(e.getMessage()); } } } From 93cf5449024a32c53c73264e0586ec577bfffd3c Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 20:47:11 +0900 Subject: [PATCH 081/128] =?UTF-8?q?fix:=20=EB=B9=88=EC=B9=B8=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EC=8B=9C=20=EC=98=88=EC=99=B8=EB=A5=BC=20IllegalAr?= =?UTF-8?q?gumentException=EC=9C=BC=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 --- src/test/java/janggi/domain/BoardTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index bc6393236d..548995794f 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,6 +1,6 @@ package janggi.domain; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.board.Board; @@ -102,7 +102,7 @@ void failure() { Position position = Position.valueOf(1, 1); Board board = new Board(new LinkedHashMap<>()); - assertThatIllegalStateException() + assertThatIllegalArgumentException() .isThrownBy(() -> board.getPieceInPosition(position)); } } From ca133d4906dca9503f87d5fd34e7561818c1d7ec Mon Sep 17 00:00:00 2001 From: mvg01 Date: Tue, 31 Mar 2026 21:08:38 +0900 Subject: [PATCH 082/128] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=20=EB=A9=94=EC=8B=9C=EC=A7=80=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/janggi/controller/JanggiController.java | 1 + src/main/java/janggi/view/OutputView.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index caec3424ec..2b2df21739 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -36,6 +36,7 @@ public void run() { board.changeBoard(from, to); turnManager.changeTurn(); } + OutputView.printGameOverMessage(turnManager.currentTeamType()); } private Team setupRedTeam() { diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index b1af2a9d96..c3960fb860 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -46,4 +46,8 @@ public static void printInputFromPosition() { public static void printInputToPosition() { System.out.println("이동하고 싶은 위치를 n,n 형태로 입력해주세요."); } + + public static void printGameOverMessage(String teamType) { + System.out.println(teamType + "의 승리로 게임이 종료되었습니다."); + } } From 78603c90df77bec95fb2e687966b60310c631c84 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 12:38:18 +0900 Subject: [PATCH 083/128] refactor: SetupCommand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SetupCommand -> SetupStrategy 네이밍 수정 - setupTypeNumber를 입력받아서 차림법 정책을 return하도록 변경 --- .../janggi/domain/command/SetupStrategy.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/java/janggi/domain/command/SetupStrategy.java diff --git a/src/main/java/janggi/domain/command/SetupStrategy.java b/src/main/java/janggi/domain/command/SetupStrategy.java new file mode 100644 index 0000000000..63b51f93fe --- /dev/null +++ b/src/main/java/janggi/domain/command/SetupStrategy.java @@ -0,0 +1,41 @@ +package janggi.domain.command; + +import janggi.domain.setup.ElephantFormation; +import janggi.domain.setup.InnerElephantElephantFormation; +import janggi.domain.setup.LeftElephantElephantFormation; +import janggi.domain.setup.OuterElephantElephantFormation; +import janggi.domain.setup.RightElephantElephantFormation; +import java.util.function.Supplier; + +public enum SetupStrategy { + + INNER_ELEPHANT(1, InnerElephantElephantFormation::new), + OUTER_ELEPHANT(2, OuterElephantElephantFormation::new), + LEFT_ELEPHANT(3, LeftElephantElephantFormation::new), + RIGHT_ELEPHANT(4, RightElephantElephantFormation::new); + + private static final int MIN_SETUP_COMMAND = 1; + private static final int MAX_SETUP_COMMAND = 4; + + private final int setupTypeNumber; + private final Supplier policySupplier; + + SetupStrategy(final int setupTypeNumber, final Supplier policySupplier) { + this.setupTypeNumber = setupTypeNumber; + this.policySupplier = policySupplier; + } + + public static SetupStrategy from(final int setupTypeNumber) { + for (SetupStrategy setup : SetupStrategy.values()) { + if (setup.setupTypeNumber == setupTypeNumber) { + return setup; + } + } + throw new IllegalArgumentException("입력은 " + MIN_SETUP_COMMAND + "에서 " + MAX_SETUP_COMMAND + "까지의 정수 값이어야 합니다."); + } + + + public ElephantFormation toPolicy() { + return policySupplier.get(); + } +} From 54d5a23baa9fda1f753043ecbef8cbf0ad8203da Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 12:39:03 +0900 Subject: [PATCH 084/128] =?UTF-8?q?refactor:=20SetupStrategy=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/controller/JanggiController.java | 18 ++++++------- .../janggi/domain/command/SetupCommand.java | 26 ------------------- src/main/java/janggi/view/InputView.java | 11 +------- 3 files changed, 9 insertions(+), 46 deletions(-) delete mode 100644 src/main/java/janggi/domain/command/SetupCommand.java diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 2b2df21739..5c8031e57b 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -3,7 +3,7 @@ import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; -import janggi.domain.command.SetupCommand; +import janggi.domain.command.SetupStrategy; import janggi.domain.piece.Piece; import janggi.domain.setup.ElephantFormation; import janggi.domain.team.BlueTeam; @@ -22,9 +22,7 @@ public JanggiController() { } public void run() { - Team redTeam = setupRedTeam(); - Team blueTeam = setupBlueTeam(); - Board board = BoardGenerator.generate(redTeam, blueTeam); + Board board = BoardGenerator.generate(setupRedTeam(), setupBlueTeam()); TurnManager turnManager = new TurnManager(); while (board.hasTwoGeneral()) { OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); @@ -41,21 +39,21 @@ public void run() { private Team setupRedTeam() { OutputView.printSetupGuide(TeamType.RED); - final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); - final ElephantFormation elephantFormation = setupCommand.toPolicy(); + final SetupStrategy setupStrategyCommand = RetryExecutor.retry(this::readSetupCommand); + final ElephantFormation elephantFormation = setupStrategyCommand.toPolicy(); return new RedTeam(elephantFormation); } private Team setupBlueTeam() { OutputView.printSetupGuide(TeamType.BLUE); - final SetupCommand setupCommand = RetryExecutor.retry(this::readSetupCommand); - final ElephantFormation elephantFormation = setupCommand.toPolicy(); + final SetupStrategy setupStrategyCommand = RetryExecutor.retry(this::readSetupCommand); + final ElephantFormation elephantFormation = setupStrategyCommand.toPolicy(); return new BlueTeam(elephantFormation); } - private SetupCommand readSetupCommand() { + private SetupStrategy readSetupCommand() { int inputCommand = InputView.readSetupCommand(); - return SetupCommand.values()[inputCommand - 1]; + return SetupStrategy.from(inputCommand); } private Position findFromPosition(Board board, TurnManager turnManager) { diff --git a/src/main/java/janggi/domain/command/SetupCommand.java b/src/main/java/janggi/domain/command/SetupCommand.java deleted file mode 100644 index 1647d272e1..0000000000 --- a/src/main/java/janggi/domain/command/SetupCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package janggi.domain.command; - -import janggi.domain.setup.ElephantFormation; -import janggi.domain.setup.InnerElephantElephantFormation; -import janggi.domain.setup.LeftElephantElephantFormation; -import janggi.domain.setup.OuterElephantElephantFormation; -import janggi.domain.setup.RightElephantElephantFormation; -import java.util.function.Supplier; - -public enum SetupCommand { - - INNER_ELEPHANT(InnerElephantElephantFormation::new), - OUTER_ELEPHANT(OuterElephantElephantFormation::new), - LEFT_ELEPHANT(LeftElephantElephantFormation::new), - RIGHT_ELEPHANT(RightElephantElephantFormation::new); - - private final Supplier policySupplier; - - SetupCommand(final Supplier setupPolicySupplier) { - this.policySupplier = setupPolicySupplier; - } - - public ElephantFormation toPolicy() { - return policySupplier.get(); - } -} diff --git a/src/main/java/janggi/view/InputView.java b/src/main/java/janggi/view/InputView.java index d08dd8a90e..8d05b62cd0 100644 --- a/src/main/java/janggi/view/InputView.java +++ b/src/main/java/janggi/view/InputView.java @@ -10,20 +10,11 @@ import janggi.view.reader.Console; public final class InputView { - - private static final int MIN_SETUP_COMMAND = 1; - private static final int MAX_SETUP_COMMAND = 4; - private InputView() { } public static int readSetupCommand() { - int inputCommand = Parser.parseInteger(Console.readLine()); - if (inputCommand >= MIN_SETUP_COMMAND && inputCommand <= MAX_SETUP_COMMAND) { - return inputCommand; - } - throw new IllegalArgumentException( - "명령 번호는 " + MIN_SETUP_COMMAND + "에서 " + MAX_SETUP_COMMAND + "까지의 정수 값이어야 합니다."); + return Parser.parseInteger(Console.readLine()); } public static Position readPosition() { From ae02236a1f8964a22643f29d933b9064252ef2b0 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 12:46:39 +0900 Subject: [PATCH 085/128] =?UTF-8?q?refactor:=20controller=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/controller/JanggiController.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 5c8031e57b..85b28c4053 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -25,14 +25,7 @@ public void run() { Board board = BoardGenerator.generate(setupRedTeam(), setupBlueTeam()); TurnManager turnManager = new TurnManager(); while (board.hasTwoGeneral()) { - OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); - Position from = findFromPosition(board, turnManager); - Piece piece = board.getPieceInPosition(from); - List movable = piece.calculateMovablePositions(from, board); - OutputView.printBoardWithMovable(BoardDto.from(board, movable)); - Position to = RetryExecutor.retry(() -> inputToPosition(movable)); - board.changeBoard(from, to); - turnManager.changeTurn(); + playTurn(board, turnManager); } OutputView.printGameOverMessage(turnManager.currentTeamType()); } @@ -56,6 +49,17 @@ private SetupStrategy readSetupCommand() { return SetupStrategy.from(inputCommand); } + private void playTurn(Board board, TurnManager turnManager) { + OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); + Position from = findFromPosition(board, turnManager); + Piece piece = board.getPieceInPosition(from); + List movable = piece.calculateMovablePositions(from, board); + OutputView.printBoardWithMovable(BoardDto.from(board, movable)); + Position to = RetryExecutor.retry(() -> inputToPosition(movable)); + board.changeBoard(from, to); + turnManager.changeTurn(); + } + private Position findFromPosition(Board board, TurnManager turnManager) { while (true) { Position from = RetryExecutor.retry(() -> inputFromPosition(board, turnManager)); From e2df58fe8a2f99364c71fb5f22c61cca78c32194 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 15:39:11 +0900 Subject: [PATCH 086/128] =?UTF-8?q?refactor:=20CannonMoveRule=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=9D=B8=EB=9D=BC=EC=9D=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/movement/CannonMoveRule.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index 30dbe177e7..9390143b75 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -24,8 +24,7 @@ public List execute(Position from, final BoardMediator boardMediator) if (isInvalidBridge(from, boardMediator)) { return List.of(); } - final List traces = new ArrayList<>(movement.calculateTraces(from, piece, boardMediator)); - return traces; + return new ArrayList<>(movement.calculateTraces(from, piece, boardMediator)); } // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) From f1e051b22c9dc60403b14dafcd5ee105c490ad56 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 16:08:45 +0900 Subject: [PATCH 087/128] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Board.java: changeBoard -> movePiece - TurnManager.java: checkFromTurn -> isCurrentTurnOf - Board.java: isNotBlank -> hasPieceIn --- src/main/java/janggi/controller/JanggiController.java | 4 ++-- src/main/java/janggi/domain/board/Board.java | 8 ++++---- src/main/java/janggi/domain/team/TurnManager.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 85b28c4053..597459364d 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -56,7 +56,7 @@ private void playTurn(Board board, TurnManager turnManager) { List movable = piece.calculateMovablePositions(from, board); OutputView.printBoardWithMovable(BoardDto.from(board, movable)); Position to = RetryExecutor.retry(() -> inputToPosition(movable)); - board.changeBoard(from, to); + board.movePiece(from, to); turnManager.changeTurn(); } @@ -78,7 +78,7 @@ private Position inputFromPosition(Board board, TurnManager turnManager) { OutputView.printInputFromPosition(); Position from = InputView.readPosition(); Piece piece = board.getPieceInPosition(from); - if (!turnManager.checkFromTurn(piece)) { + if (!turnManager.isCurrentTurnOf(piece)) { throw new IllegalArgumentException("자신의 기물을 선택하세요."); } return from; diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index fca02fc264..e7f9f43cca 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -13,13 +13,13 @@ public Board(final Map positionPieceMap) { this.positionPieceMap = positionPieceMap; } - public void changeBoard(final Position from, final Position to) { + public void movePiece(final Position from, final Position to) { positionPieceMap.put(to, positionPieceMap.remove(from)); } @Override public boolean hasPieceAt(final Position position) { - return isNotBlank(position); + return hasPieceIn(position); } @Override @@ -39,12 +39,12 @@ public boolean hasTwoGeneral() { } - private boolean isNotBlank(final Position position) { + private boolean hasPieceIn(final Position position) { return positionPieceMap.containsKey(position); } private Piece findPieceByPosition(final Position position) { - if (!isNotBlank(position)) { + if (!hasPieceIn(position)) { throw new IllegalArgumentException("요청된 위치에는 기물이 존재하지 않습니다."); } return positionPieceMap.get(position); diff --git a/src/main/java/janggi/domain/team/TurnManager.java b/src/main/java/janggi/domain/team/TurnManager.java index c84bb1b3e3..94a0e64194 100644 --- a/src/main/java/janggi/domain/team/TurnManager.java +++ b/src/main/java/janggi/domain/team/TurnManager.java @@ -13,7 +13,7 @@ public void changeTurn() { this.currentTurnTeamType = currentTurnTeamType.nextTeamType(); } - public boolean checkFromTurn(Piece piece) { + public boolean isCurrentTurnOf(Piece piece) { return piece.getTeamType() == currentTurnTeamType; } From 80b0ec3eafcad37b8cd61a5fe6996ae4604fca1b Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 16:11:58 +0900 Subject: [PATCH 088/128] =?UTF-8?q?refactor:=20TurnManager=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=A7=A4=EA=B0=9C?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/controller/JanggiController.java | 2 +- src/main/java/janggi/domain/team/TurnManager.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 597459364d..619dbcee5d 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -78,7 +78,7 @@ private Position inputFromPosition(Board board, TurnManager turnManager) { OutputView.printInputFromPosition(); Position from = InputView.readPosition(); Piece piece = board.getPieceInPosition(from); - if (!turnManager.isCurrentTurnOf(piece)) { + if (!turnManager.isCurrentTurnOf(piece.getTeamType())) { throw new IllegalArgumentException("자신의 기물을 선택하세요."); } return from; diff --git a/src/main/java/janggi/domain/team/TurnManager.java b/src/main/java/janggi/domain/team/TurnManager.java index 94a0e64194..dc626c6965 100644 --- a/src/main/java/janggi/domain/team/TurnManager.java +++ b/src/main/java/janggi/domain/team/TurnManager.java @@ -1,7 +1,5 @@ package janggi.domain.team; -import janggi.domain.piece.Piece; - public class TurnManager { private TeamType currentTurnTeamType; @@ -13,8 +11,8 @@ public void changeTurn() { this.currentTurnTeamType = currentTurnTeamType.nextTeamType(); } - public boolean isCurrentTurnOf(Piece piece) { - return piece.getTeamType() == currentTurnTeamType; + public boolean isCurrentTurnOf(TeamType teamType) { + return this.currentTurnTeamType == teamType; } public String currentTeamType() { From f7c46aefc966aa7456ab69db35f471edc68803da Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 17:02:29 +0900 Subject: [PATCH 089/128] =?UTF-8?q?refactor:=20SlidingMoveRule=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/movement/SlidingMoveRule.java | 7 +++---- src/main/java/janggi/domain/piece/Chariot.java | 8 ++++---- src/main/java/janggi/domain/piece/General.java | 16 ++++++++-------- src/main/java/janggi/domain/piece/Guard.java | 16 ++++++++-------- src/main/java/janggi/domain/piece/Soldier.java | 12 ++++++------ .../domain/movement/SlidingMoveRuleTest.java | 4 +--- 6 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/main/java/janggi/domain/movement/SlidingMoveRule.java b/src/main/java/janggi/domain/movement/SlidingMoveRule.java index 2972dc455e..3d3b9c2e0c 100644 --- a/src/main/java/janggi/domain/movement/SlidingMoveRule.java +++ b/src/main/java/janggi/domain/movement/SlidingMoveRule.java @@ -7,16 +7,15 @@ public class SlidingMoveRule implements MoveRule { - private final List movementOrder; + private final Movement movementOrder; - public SlidingMoveRule(final List movementOrder) { + public SlidingMoveRule(Movement movementOrder) { this.movementOrder = movementOrder; } @Override public List execute(Position from, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); - final Movement movement = movementOrder.getFirst(); - return movement.calculateTraces(from, piece, boardMediator); + return movementOrder.calculateTraces(from, piece, boardMediator); } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index a3f7cb623d..2fefafcebc 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -19,10 +19,10 @@ public class Chariot implements Piece { static { final List movementStrategies = List.of( - new SlidingMoveRule(List.of(new Movement(MAXIMUM_ROW, Direction.UP))), - new SlidingMoveRule(List.of(new Movement(MAXIMUM_ROW, Direction.DOWN))), - new SlidingMoveRule(List.of(new Movement(MAXIMUM_COLUMN, Direction.RIGHT))), - new SlidingMoveRule(List.of(new Movement(MAXIMUM_COLUMN, Direction.LEFT)))); + new SlidingMoveRule(new Movement(MAXIMUM_ROW, Direction.UP)), + new SlidingMoveRule(new Movement(MAXIMUM_ROW, Direction.DOWN)), + new SlidingMoveRule(new Movement(MAXIMUM_COLUMN, Direction.RIGHT)), + new SlidingMoveRule(new Movement(MAXIMUM_COLUMN, Direction.LEFT))); PIECE_ACTION = new PieceAction(movementStrategies); } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 6fd3ba5753..2e28560a01 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -16,14 +16,14 @@ public class General implements Piece { static { final List movementStrategies = List.of( - new SlidingMoveRule(List.of(new Movement(1, Direction.UP_LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.UP))), - new SlidingMoveRule(List.of(new Movement(1, Direction.UP_RIGHT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_RIGHT)))); + new SlidingMoveRule(new Movement(1, Direction.UP_LEFT)), + new SlidingMoveRule(new Movement(1, Direction.UP)), + new SlidingMoveRule(new Movement(1, Direction.UP_RIGHT)), + new SlidingMoveRule(new Movement(1, Direction.LEFT)), + new SlidingMoveRule(new Movement(1, Direction.RIGHT)), + new SlidingMoveRule(new Movement(1, Direction.DOWN_LEFT)), + new SlidingMoveRule(new Movement(1, Direction.DOWN)), + new SlidingMoveRule(new Movement(1, Direction.DOWN_RIGHT))); PIECE_ACTION = new PieceAction(movementStrategies); } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 9c97c3fe9a..4a12475cf3 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -16,14 +16,14 @@ public class Guard implements Piece { static { final List movementStrategies = List.of( - new SlidingMoveRule(List.of(new Movement(1, Direction.UP_LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.UP))), - new SlidingMoveRule(List.of(new Movement(1, Direction.UP_RIGHT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN_RIGHT)))); + new SlidingMoveRule(new Movement(1, Direction.UP_LEFT)), + new SlidingMoveRule(new Movement(1, Direction.UP)), + new SlidingMoveRule(new Movement(1, Direction.UP_RIGHT)), + new SlidingMoveRule(new Movement(1, Direction.LEFT)), + new SlidingMoveRule(new Movement(1, Direction.RIGHT)), + new SlidingMoveRule(new Movement(1, Direction.DOWN_LEFT)), + new SlidingMoveRule(new Movement(1, Direction.DOWN)), + new SlidingMoveRule(new Movement(1, Direction.DOWN_RIGHT))); PIECE_ACTION = new PieceAction(movementStrategies); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 3f716300b9..ae4df180f5 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -17,13 +17,13 @@ public class Soldier implements Piece { static { final List redMovementStrategies = List.of( - new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.DOWN)))); + new SlidingMoveRule(new Movement(1, Direction.LEFT)), + new SlidingMoveRule(new Movement(1, Direction.RIGHT)), + new SlidingMoveRule(new Movement(1, Direction.DOWN))); final List blueMovementStrategies = List.of( - new SlidingMoveRule(List.of(new Movement(1, Direction.LEFT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.RIGHT))), - new SlidingMoveRule(List.of(new Movement(1, Direction.UP)))); + new SlidingMoveRule(new Movement(1, Direction.LEFT)), + new SlidingMoveRule(new Movement(1, Direction.RIGHT)), + new SlidingMoveRule(new Movement(1, Direction.UP))); RED_PIECE_ACTION = new PieceAction(redMovementStrategies); BLUE_PIECE_ACTION = new PieceAction(blueMovementStrategies); } diff --git a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java index 664078fa60..6f39a90034 100644 --- a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java @@ -26,9 +26,7 @@ public void execute() { ); Board board = new Board(positionPieceMap); Direction direction = Direction.DOWN; - MoveRule moveRuleWithTraces = new SlidingMoveRule( - List.of(new Movement(MAXIMUM_ROW, direction)) - ); + MoveRule moveRuleWithTraces = new SlidingMoveRule(new Movement(MAXIMUM_ROW, direction)); Position from = Position.valueOf(5, 3); // when From 9b02da6d28b5066a0b8550ac8e3721862fe6f246 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 17:32:04 +0900 Subject: [PATCH 090/128] =?UTF-8?q?refactor:=20setup=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EB=8A=94=20=EB=A7=B5=EC=9D=84=20?= =?UTF-8?q?=EB=AA=A8=EB=91=90=20=EB=B6=88=EB=B3=80=EC=9C=BC=EB=A1=9C=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 --- .../domain/setup/ElephantFormation.java | 28 ++++++++++--------- .../setup/InnerElephantElephantFormation.java | 2 +- .../setup/LeftElephantElephantFormation.java | 2 +- .../setup/OuterElephantElephantFormation.java | 2 +- .../setup/RightElephantElephantFormation.java | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/main/java/janggi/domain/setup/ElephantFormation.java b/src/main/java/janggi/domain/setup/ElephantFormation.java index d00bfb2fb8..bf9271cf3c 100644 --- a/src/main/java/janggi/domain/setup/ElephantFormation.java +++ b/src/main/java/janggi/domain/setup/ElephantFormation.java @@ -2,6 +2,7 @@ import janggi.domain.Position; import janggi.domain.piece.PieceType; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -9,19 +10,20 @@ public abstract class ElephantFormation { static final Map COMMON_BOARD_MAP; static { - COMMON_BOARD_MAP = new LinkedHashMap<>(); - COMMON_BOARD_MAP.put(Position.valueOf(1, 1), PieceType.CHARIOT); - COMMON_BOARD_MAP.put(Position.valueOf(1, 4), PieceType.GUARD); - COMMON_BOARD_MAP.put(Position.valueOf(1, 6), PieceType.GUARD); - COMMON_BOARD_MAP.put(Position.valueOf(1, 9), PieceType.CHARIOT); - COMMON_BOARD_MAP.put(Position.valueOf(2, 5), PieceType.GENERAL); - COMMON_BOARD_MAP.put(Position.valueOf(3, 2), PieceType.CANNON); - COMMON_BOARD_MAP.put(Position.valueOf(3, 8), PieceType.CANNON); - COMMON_BOARD_MAP.put(Position.valueOf(4, 1), PieceType.SOLDIER); - COMMON_BOARD_MAP.put(Position.valueOf(4, 3), PieceType.SOLDIER); - COMMON_BOARD_MAP.put(Position.valueOf(4, 5), PieceType.SOLDIER); - COMMON_BOARD_MAP.put(Position.valueOf(4, 7), PieceType.SOLDIER); - COMMON_BOARD_MAP.put(Position.valueOf(4, 9), PieceType.SOLDIER); + Map boardMap = new LinkedHashMap<>(); + boardMap.put(Position.valueOf(1, 1), PieceType.CHARIOT); + boardMap.put(Position.valueOf(1, 4), PieceType.GUARD); + boardMap.put(Position.valueOf(1, 6), PieceType.GUARD); + boardMap.put(Position.valueOf(1, 9), PieceType.CHARIOT); + boardMap.put(Position.valueOf(2, 5), PieceType.GENERAL); + boardMap.put(Position.valueOf(3, 2), PieceType.CANNON); + boardMap.put(Position.valueOf(3, 8), PieceType.CANNON); + boardMap.put(Position.valueOf(4, 1), PieceType.SOLDIER); + boardMap.put(Position.valueOf(4, 3), PieceType.SOLDIER); + boardMap.put(Position.valueOf(4, 5), PieceType.SOLDIER); + boardMap.put(Position.valueOf(4, 7), PieceType.SOLDIER); + boardMap.put(Position.valueOf(4, 9), PieceType.SOLDIER); + COMMON_BOARD_MAP = Collections.unmodifiableMap(boardMap); } public abstract Map offerBoardMap(); diff --git a/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java b/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java index 8fa3e36731..3569254936 100644 --- a/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java +++ b/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java @@ -14,6 +14,6 @@ public Map offerBoardMap() { boardMap.put(Position.valueOf(1, 3), PieceType.ELEPHANT); boardMap.put(Position.valueOf(1, 7), PieceType.ELEPHANT); boardMap.put(Position.valueOf(1, 8), PieceType.HORSE); - return boardMap; + return Map.copyOf(boardMap); } } diff --git a/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java b/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java index 3a1f6a6ab0..2c45fe9b66 100644 --- a/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java +++ b/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java @@ -13,6 +13,6 @@ public Map offerBoardMap() { boardMap.put(Position.valueOf(1, 3), PieceType.HORSE); boardMap.put(Position.valueOf(1, 7), PieceType.ELEPHANT); boardMap.put(Position.valueOf(1, 8), PieceType.HORSE); - return boardMap; + return Map.copyOf(boardMap); } } diff --git a/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java b/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java index 5470397227..5e936b26a1 100644 --- a/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java +++ b/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java @@ -13,6 +13,6 @@ public Map offerBoardMap() { boardMap.put(Position.valueOf(1, 3), PieceType.HORSE); boardMap.put(Position.valueOf(1, 7), PieceType.HORSE); boardMap.put(Position.valueOf(1, 8), PieceType.ELEPHANT); - return boardMap; + return Map.copyOf(boardMap); } } diff --git a/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java b/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java index 3febdc2fa7..59eca21e98 100644 --- a/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java +++ b/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java @@ -13,6 +13,6 @@ public Map offerBoardMap() { boardMap.put(Position.valueOf(1, 3), PieceType.ELEPHANT); boardMap.put(Position.valueOf(1, 7), PieceType.HORSE); boardMap.put(Position.valueOf(1, 8), PieceType.ELEPHANT); - return boardMap; + return Map.copyOf(boardMap); } } From 2109d0e5562d829a0d82b77ca80c292c7e07a1b0 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 17:41:02 +0900 Subject: [PATCH 091/128] =?UTF-8?q?refactor:=20board=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=EC=97=90=20=EB=B0=A9=EC=96=B4=EC=A0=81=20=EB=B3=B5?= =?UTF-8?q?=EC=82=AC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Board.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index e7f9f43cca..0da66a622d 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; +import java.util.LinkedHashMap; import java.util.Map; public class Board implements BoardMediator { @@ -10,7 +11,7 @@ public class Board implements BoardMediator { private final Map positionPieceMap; public Board(final Map positionPieceMap) { - this.positionPieceMap = positionPieceMap; + this.positionPieceMap = new LinkedHashMap<>(positionPieceMap); } public void movePiece(final Position from, final Position to) { From dc7e3aab7c660033162f84e91b7eaacd39782de4 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 17:51:20 +0900 Subject: [PATCH 092/128] =?UTF-8?q?test:=20SlidingMoveRuleTest=20=EB=B3=B4?= =?UTF-8?q?=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/SlidingMoveRuleTest.java | 70 ++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java index 6f39a90034..27c0c99475 100644 --- a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java @@ -8,6 +8,7 @@ import janggi.domain.piece.Chariot; import janggi.domain.piece.Elephant; import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.List; import java.util.Map; @@ -17,8 +18,8 @@ public class SlidingMoveRuleTest { @Test - @DisplayName("이동 가능한 자취 경로 계산 테스트") - public void execute() { + @DisplayName("적이 있는 곳 까지 이동할 수 있다") + public void success1() { // given Map positionPieceMap = Map.of( Position.valueOf(5, 3), new Chariot(TeamType.RED), @@ -40,4 +41,69 @@ public void execute() { ); assertThat(actual).hasSameElementsAs(expected); } + + @Test + @DisplayName("아군이 있는 곳 까지 이동할 수 있다") + public void success2() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Chariot(TeamType.RED), + Position.valueOf(8, 3), new Soldier(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + Direction direction = Direction.DOWN; + MoveRule moveRuleWithTraces = new SlidingMoveRule(new Movement(MAXIMUM_ROW, direction)); + Position from = Position.valueOf(5, 3); + + // when + List actual = moveRuleWithTraces.execute(from, board); + + // then + List expected = List.of( + Position.valueOf(6, 3), + Position.valueOf(7, 3) + ); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("장기판 경계 까지 이동할 수 있다") + public void success3() { + // given + Map positionPieceMap = Map.of(Position.valueOf(5, 3), new Chariot(TeamType.RED)); + Board board = new Board(positionPieceMap); + Direction direction = Direction.UP; + MoveRule moveRuleWithTraces = new SlidingMoveRule(new Movement(MAXIMUM_ROW, direction)); + Position from = Position.valueOf(5, 3); + + // when + List actual = moveRuleWithTraces.execute(from, board); + + // then + List expected = List.of( + Position.valueOf(1, 3), + Position.valueOf(2, 3), + Position.valueOf(3, 3), + Position.valueOf(4, 3) + ); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("장기판 경계에선 더 이동할 수 없다") + public void success4() { + // given + Map positionPieceMap = Map.of(Position.valueOf(1, 3), new Chariot(TeamType.RED)); + Board board = new Board(positionPieceMap); + Direction direction = Direction.UP; + MoveRule moveRuleWithTraces = new SlidingMoveRule(new Movement(MAXIMUM_ROW, direction)); + Position from = Position.valueOf(1, 3); + + // when + List actual = moveRuleWithTraces.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } } From 99a49018e4bc0202a0823a321183627e58c16ac6 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:00:13 +0900 Subject: [PATCH 093/128] =?UTF-8?q?refactor:=20SetupStrategy=20setup=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/controller/JanggiController.java | 2 +- .../janggi/domain/{command => setup}/SetupStrategy.java | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) rename src/main/java/janggi/domain/{command => setup}/SetupStrategy.java (79%) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 619dbcee5d..2c5120a271 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -3,9 +3,9 @@ import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; -import janggi.domain.command.SetupStrategy; import janggi.domain.piece.Piece; import janggi.domain.setup.ElephantFormation; +import janggi.domain.setup.SetupStrategy; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import janggi.domain.team.Team; diff --git a/src/main/java/janggi/domain/command/SetupStrategy.java b/src/main/java/janggi/domain/setup/SetupStrategy.java similarity index 79% rename from src/main/java/janggi/domain/command/SetupStrategy.java rename to src/main/java/janggi/domain/setup/SetupStrategy.java index 63b51f93fe..7659d3959c 100644 --- a/src/main/java/janggi/domain/command/SetupStrategy.java +++ b/src/main/java/janggi/domain/setup/SetupStrategy.java @@ -1,10 +1,5 @@ -package janggi.domain.command; +package janggi.domain.setup; -import janggi.domain.setup.ElephantFormation; -import janggi.domain.setup.InnerElephantElephantFormation; -import janggi.domain.setup.LeftElephantElephantFormation; -import janggi.domain.setup.OuterElephantElephantFormation; -import janggi.domain.setup.RightElephantElephantFormation; import java.util.function.Supplier; public enum SetupStrategy { From b15d18e8df6bba93c9ea5f30cb89cf58ede84bd6 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:30:05 +0900 Subject: [PATCH 094/128] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/{ => board}/BoardGeneratorTest.java | 4 +--- src/test/java/janggi/domain/{ => board}/BoardTest.java | 4 ++-- .../janggi/{ => domain}/fixture/SetupPolicyTestFixture.java | 4 ++-- .../java/janggi/domain/{ => piece}/BlueSoldierTest.java | 5 ++--- src/test/java/janggi/domain/{ => piece}/CannonTest.java | 6 ++---- src/test/java/janggi/domain/{ => piece}/ChariotTest.java | 6 ++---- src/test/java/janggi/domain/{ => piece}/ElephantTest.java | 6 ++---- src/test/java/janggi/domain/{ => piece}/GeneralTest.java | 6 ++---- src/test/java/janggi/domain/{ => piece}/GuardTest.java | 6 ++---- src/test/java/janggi/domain/{ => piece}/HorseTest.java | 6 ++---- src/test/java/janggi/domain/{ => piece}/PieceTest.java | 4 +--- src/test/java/janggi/domain/{ => piece}/RedSoldierTest.java | 5 ++--- .../{ => setup}/InnerElephantElephantFormationTest.java | 6 +++--- .../{ => setup}/LeftElephantElephantFormationTest.java | 6 +++--- .../{ => setup}/OuterElephantElephantFormationTest.java | 6 +++--- .../{ => setup}/RightElephantElephantFormationTest.java | 6 +++--- 16 files changed, 34 insertions(+), 52 deletions(-) rename src/test/java/janggi/domain/{ => board}/BoardGeneratorTest.java (90%) rename src/test/java/janggi/domain/{ => board}/BoardTest.java (98%) rename src/test/java/janggi/{ => domain}/fixture/SetupPolicyTestFixture.java (97%) rename src/test/java/janggi/domain/{ => piece}/BlueSoldierTest.java (97%) rename src/test/java/janggi/domain/{ => piece}/CannonTest.java (96%) rename src/test/java/janggi/domain/{ => piece}/ChariotTest.java (96%) rename src/test/java/janggi/domain/{ => piece}/ElephantTest.java (96%) rename src/test/java/janggi/domain/{ => piece}/GeneralTest.java (96%) rename src/test/java/janggi/domain/{ => piece}/GuardTest.java (96%) rename src/test/java/janggi/domain/{ => piece}/HorseTest.java (96%) rename src/test/java/janggi/domain/{ => piece}/PieceTest.java (92%) rename src/test/java/janggi/domain/{ => piece}/RedSoldierTest.java (97%) rename src/test/java/janggi/domain/{ => setup}/InnerElephantElephantFormationTest.java (88%) rename src/test/java/janggi/domain/{ => setup}/LeftElephantElephantFormationTest.java (89%) rename src/test/java/janggi/domain/{ => setup}/OuterElephantElephantFormationTest.java (88%) rename src/test/java/janggi/domain/{ => setup}/RightElephantElephantFormationTest.java (88%) diff --git a/src/test/java/janggi/domain/BoardGeneratorTest.java b/src/test/java/janggi/domain/board/BoardGeneratorTest.java similarity index 90% rename from src/test/java/janggi/domain/BoardGeneratorTest.java rename to src/test/java/janggi/domain/board/BoardGeneratorTest.java index 5dfbce76d3..840241bde1 100644 --- a/src/test/java/janggi/domain/BoardGeneratorTest.java +++ b/src/test/java/janggi/domain/board/BoardGeneratorTest.java @@ -1,9 +1,7 @@ -package janggi.domain; +package janggi.domain.board; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.board.Board; -import janggi.domain.board.BoardGenerator; import janggi.domain.setup.InnerElephantElephantFormation; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java similarity index 98% rename from src/test/java/janggi/domain/BoardTest.java rename to src/test/java/janggi/domain/board/BoardTest.java index 548995794f..d3b2d0e5fe 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -1,9 +1,9 @@ -package janggi.domain; +package janggi.domain.board; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.board.Board; +import janggi.domain.Position; import janggi.domain.piece.Cannon; import janggi.domain.piece.General; import janggi.domain.piece.Piece; diff --git a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java b/src/test/java/janggi/domain/fixture/SetupPolicyTestFixture.java similarity index 97% rename from src/test/java/janggi/fixture/SetupPolicyTestFixture.java rename to src/test/java/janggi/domain/fixture/SetupPolicyTestFixture.java index dfcf109358..a000605c42 100644 --- a/src/test/java/janggi/fixture/SetupPolicyTestFixture.java +++ b/src/test/java/janggi/domain/fixture/SetupPolicyTestFixture.java @@ -1,7 +1,7 @@ -package janggi.fixture; +package janggi.domain.fixture; -import janggi.domain.piece.PieceType; import janggi.domain.Position; +import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/BlueSoldierTest.java b/src/test/java/janggi/domain/piece/BlueSoldierTest.java similarity index 97% rename from src/test/java/janggi/domain/BlueSoldierTest.java rename to src/test/java/janggi/domain/piece/BlueSoldierTest.java index 2855628a3e..88a16e1529 100644 --- a/src/test/java/janggi/domain/BlueSoldierTest.java +++ b/src/test/java/janggi/domain/piece/BlueSoldierTest.java @@ -1,10 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/CannonTest.java b/src/test/java/janggi/domain/piece/CannonTest.java similarity index 96% rename from src/test/java/janggi/domain/CannonTest.java rename to src/test/java/janggi/domain/piece/CannonTest.java index afe8d0a9de..519ab01780 100644 --- a/src/test/java/janggi/domain/CannonTest.java +++ b/src/test/java/janggi/domain/piece/CannonTest.java @@ -1,11 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.Cannon; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.List; import java.util.Map; diff --git a/src/test/java/janggi/domain/ChariotTest.java b/src/test/java/janggi/domain/piece/ChariotTest.java similarity index 96% rename from src/test/java/janggi/domain/ChariotTest.java rename to src/test/java/janggi/domain/piece/ChariotTest.java index a639b59329..f4bcdb8b73 100644 --- a/src/test/java/janggi/domain/ChariotTest.java +++ b/src/test/java/janggi/domain/piece/ChariotTest.java @@ -1,11 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.Chariot; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.ArrayList; import java.util.LinkedHashMap; diff --git a/src/test/java/janggi/domain/ElephantTest.java b/src/test/java/janggi/domain/piece/ElephantTest.java similarity index 96% rename from src/test/java/janggi/domain/ElephantTest.java rename to src/test/java/janggi/domain/piece/ElephantTest.java index 5e615c73af..6442b9cebe 100644 --- a/src/test/java/janggi/domain/ElephantTest.java +++ b/src/test/java/janggi/domain/piece/ElephantTest.java @@ -1,11 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.Elephant; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/GeneralTest.java b/src/test/java/janggi/domain/piece/GeneralTest.java similarity index 96% rename from src/test/java/janggi/domain/GeneralTest.java rename to src/test/java/janggi/domain/piece/GeneralTest.java index 4ef9e33068..0c87a85ba6 100644 --- a/src/test/java/janggi/domain/GeneralTest.java +++ b/src/test/java/janggi/domain/piece/GeneralTest.java @@ -1,11 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.General; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/GuardTest.java b/src/test/java/janggi/domain/piece/GuardTest.java similarity index 96% rename from src/test/java/janggi/domain/GuardTest.java rename to src/test/java/janggi/domain/piece/GuardTest.java index c5c4e5cafb..16d6af1692 100644 --- a/src/test/java/janggi/domain/GuardTest.java +++ b/src/test/java/janggi/domain/piece/GuardTest.java @@ -1,12 +1,10 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardMediator; -import janggi.domain.piece.Guard; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/HorseTest.java b/src/test/java/janggi/domain/piece/HorseTest.java similarity index 96% rename from src/test/java/janggi/domain/HorseTest.java rename to src/test/java/janggi/domain/piece/HorseTest.java index 8544f9d7fe..3707b640a0 100644 --- a/src/test/java/janggi/domain/HorseTest.java +++ b/src/test/java/janggi/domain/piece/HorseTest.java @@ -1,11 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.Horse; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/PieceTest.java b/src/test/java/janggi/domain/piece/PieceTest.java similarity index 92% rename from src/test/java/janggi/domain/PieceTest.java rename to src/test/java/janggi/domain/piece/PieceTest.java index 8fcaf711a4..b2b0889b06 100644 --- a/src/test/java/janggi/domain/PieceTest.java +++ b/src/test/java/janggi/domain/piece/PieceTest.java @@ -1,9 +1,7 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.piece.Cannon; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/src/test/java/janggi/domain/RedSoldierTest.java b/src/test/java/janggi/domain/piece/RedSoldierTest.java similarity index 97% rename from src/test/java/janggi/domain/RedSoldierTest.java rename to src/test/java/janggi/domain/piece/RedSoldierTest.java index d5d14a30aa..ff4e0b7462 100644 --- a/src/test/java/janggi/domain/RedSoldierTest.java +++ b/src/test/java/janggi/domain/piece/RedSoldierTest.java @@ -1,10 +1,9 @@ -package janggi.domain; +package janggi.domain.piece; import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.Position; import janggi.domain.board.Board; -import janggi.domain.piece.Piece; -import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/InnerElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java similarity index 88% rename from src/test/java/janggi/domain/InnerElephantElephantFormationTest.java rename to src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java index bb2ad0dd6a..121ac08c90 100644 --- a/src/test/java/janggi/domain/InnerElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java @@ -1,10 +1,10 @@ -package janggi.domain; +package janggi.domain.setup; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.Position; +import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; -import janggi.domain.setup.InnerElephantElephantFormation; -import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/LeftElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java similarity index 89% rename from src/test/java/janggi/domain/LeftElephantElephantFormationTest.java rename to src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java index 8e91cb65ac..ff78f4e50c 100644 --- a/src/test/java/janggi/domain/LeftElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java @@ -1,10 +1,10 @@ -package janggi.domain; +package janggi.domain.setup; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.Position; +import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; -import janggi.domain.setup.LeftElephantElephantFormation; -import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/OuterElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java similarity index 88% rename from src/test/java/janggi/domain/OuterElephantElephantFormationTest.java rename to src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java index dbe57bfadf..eadaff1d90 100644 --- a/src/test/java/janggi/domain/OuterElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java @@ -1,10 +1,10 @@ -package janggi.domain; +package janggi.domain.setup; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.Position; +import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; -import janggi.domain.setup.OuterElephantElephantFormation; -import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/RightElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java similarity index 88% rename from src/test/java/janggi/domain/RightElephantElephantFormationTest.java rename to src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java index aeecf765db..52acc44add 100644 --- a/src/test/java/janggi/domain/RightElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java @@ -1,10 +1,10 @@ -package janggi.domain; +package janggi.domain.setup; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.Position; +import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; -import janggi.domain.setup.RightElephantElephantFormation; -import janggi.fixture.SetupPolicyTestFixture; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; From 0210333c1482841dceecfc01006f522dded68bf8 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:46:13 +0900 Subject: [PATCH 095/128] =?UTF-8?q?test:=20StepMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=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 --- .../domain/movement/StepMoveRuleTest.java | 107 +++++++++++++++++- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index bee4f8b705..f728364d1b 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -6,6 +6,7 @@ import janggi.domain.board.Board; import janggi.domain.piece.Elephant; import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.List; import java.util.Map; @@ -15,8 +16,8 @@ public class StepMoveRuleTest { @Test - @DisplayName("이동 가능한 목적지 계산 테스트") - void execute() { + @DisplayName("경로와 목적지에 장애물이 없다") + void execute_1() { // given Map positionPieceMap = Map.of( Position.valueOf(5, 3), new Elephant(TeamType.RED) @@ -26,14 +27,112 @@ void execute() { new Movement(1, Direction.RIGHT), new Movement(2, Direction.UP_RIGHT) ); - MoveRule moveRuleWithNoTraces = new StepMoveRule(movementOrder); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); // when - List actual = moveRuleWithNoTraces.execute(from, board); + List actual = stepMoveRule.execute(from, board); // then List expected = List.of(Position.valueOf(3, 6)); assertThat(actual).hasSameElementsAs(expected); } + + @Test + @DisplayName("경로에 장애물이 없지만 목적지에 장애물이 있다") + void execute_2() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(3, 6), new Soldier(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 장애물이 없고 목적지에 적 기물이 있다") + void execute_3() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(3, 6), new Soldier(TeamType.BLUE) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(Position.valueOf(3, 6)); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 장애물이 있고 목적지에 적 기물이 있다") + void execute_4() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(5, 4), new Soldier(TeamType.BLUE), + Position.valueOf(6, 3), new Soldier(TeamType.BLUE) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 장애물이 있고 목적지에 적 기물이 있다") + void execute_5() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(4, 5), new Soldier(TeamType.BLUE), + Position.valueOf(6, 3), new Soldier(TeamType.BLUE) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } } From d6f20fdd00c03f00c2350aa4d9018a27737650f0 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:50:09 +0900 Subject: [PATCH 096/128] =?UTF-8?q?test:=20StepMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 현재 movement의 움직임에서 maxDistance는 1로 고정해야해서 수정 --- .../janggi/domain/movement/StepMoveRuleTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index f728364d1b..0600e14e6d 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -25,7 +25,8 @@ void execute_1() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -49,7 +50,8 @@ void execute_2() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -73,7 +75,8 @@ void execute_3() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -98,7 +101,8 @@ void execute_4() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -123,7 +127,8 @@ void execute_5() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); From 81a84a8e258e67dbd8094ddbe59944f300b2009e Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:53:28 +0900 Subject: [PATCH 097/128] =?UTF-8?q?test:=20StepMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/StepMoveRuleTest.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index 0600e14e6d..62a1566df2 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -20,7 +20,7 @@ public class StepMoveRuleTest { void execute_1() { // given Map positionPieceMap = Map.of( - Position.valueOf(5, 3), new Elephant(TeamType.RED) + Position.valueOf(5, 6), new Elephant(TeamType.RED) ); Board board = new Board(positionPieceMap); List movementOrder = List.of( @@ -29,13 +29,13 @@ void execute_1() { new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); - Position from = Position.valueOf(5, 3); + Position from = Position.valueOf(5, 6); // when List actual = stepMoveRule.execute(from, board); // then - List expected = List.of(Position.valueOf(3, 6)); + List expected = List.of(Position.valueOf(3, 9)); assertThat(actual).hasSameElementsAs(expected); } @@ -140,4 +140,28 @@ void execute_5() { List expected = List.of(); assertThat(actual).hasSameElementsAs(expected); } + + @Test + @DisplayName("보드판의 경계를 나가게 되어 목적지로 이동할 수 없다") + void execute_6() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 7), new Elephant(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 7); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } } From 33b2605435a31c15a8549ff7e3f54ae68bcddebf Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 23:28:15 +0900 Subject: [PATCH 098/128] =?UTF-8?q?test:=20CannonMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=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 --- src/main/java/janggi/domain/movement/Movement.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 08ee3255af..8d6c93d452 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -79,10 +79,15 @@ public Position findFirstOccupiedPositionOrMax(final Position from, final Piece // 경로에 장애물을 만나면 그때까지의 리스트를 반환하고, 적을 만난다면 적의 좌표를 포함하여 반환한다. public List calculateTraces(final Position from, final Piece piece, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); + Position prev = from; for (int distance = 1; distance <= maxDistance; distance++) { Position to = calculateNextPosition(from, distance); + if (prev.equals(to)) { + return traces; + } if (!hasPieceAt(to, boardMediator)) { traces.add(to); + prev = to; continue; } final Piece target = findPieceAt(to, boardMediator); From ae38ff396b4eaa1fdf9a6d9df251b8046c4eba29 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:46:13 +0900 Subject: [PATCH 099/128] =?UTF-8?q?test:=20StepMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=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 --- .../domain/movement/StepMoveRuleTest.java | 107 +++++++++++++++++- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index bee4f8b705..f728364d1b 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -6,6 +6,7 @@ import janggi.domain.board.Board; import janggi.domain.piece.Elephant; import janggi.domain.piece.Piece; +import janggi.domain.piece.Soldier; import janggi.domain.team.TeamType; import java.util.List; import java.util.Map; @@ -15,8 +16,8 @@ public class StepMoveRuleTest { @Test - @DisplayName("이동 가능한 목적지 계산 테스트") - void execute() { + @DisplayName("경로와 목적지에 장애물이 없다") + void execute_1() { // given Map positionPieceMap = Map.of( Position.valueOf(5, 3), new Elephant(TeamType.RED) @@ -26,14 +27,112 @@ void execute() { new Movement(1, Direction.RIGHT), new Movement(2, Direction.UP_RIGHT) ); - MoveRule moveRuleWithNoTraces = new StepMoveRule(movementOrder); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); // when - List actual = moveRuleWithNoTraces.execute(from, board); + List actual = stepMoveRule.execute(from, board); // then List expected = List.of(Position.valueOf(3, 6)); assertThat(actual).hasSameElementsAs(expected); } + + @Test + @DisplayName("경로에 장애물이 없지만 목적지에 장애물이 있다") + void execute_2() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(3, 6), new Soldier(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 장애물이 없고 목적지에 적 기물이 있다") + void execute_3() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(3, 6), new Soldier(TeamType.BLUE) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(Position.valueOf(3, 6)); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 장애물이 있고 목적지에 적 기물이 있다") + void execute_4() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(5, 4), new Soldier(TeamType.BLUE), + Position.valueOf(6, 3), new Soldier(TeamType.BLUE) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("경로에 장애물이 있고 목적지에 적 기물이 있다") + void execute_5() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 3), new Elephant(TeamType.RED), + Position.valueOf(4, 5), new Soldier(TeamType.BLUE), + Position.valueOf(6, 3), new Soldier(TeamType.BLUE) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(2, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 3); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } } From 4f108d1307029bf5fd79e99d3cfeb64f0a3560ce Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:50:09 +0900 Subject: [PATCH 100/128] =?UTF-8?q?test:=20StepMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 현재 movement의 움직임에서 maxDistance는 1로 고정해야해서 수정 --- .../janggi/domain/movement/StepMoveRuleTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index f728364d1b..0600e14e6d 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -25,7 +25,8 @@ void execute_1() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -49,7 +50,8 @@ void execute_2() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -73,7 +75,8 @@ void execute_3() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -98,7 +101,8 @@ void execute_4() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); @@ -123,7 +127,8 @@ void execute_5() { Board board = new Board(positionPieceMap); List movementOrder = List.of( new Movement(1, Direction.RIGHT), - new Movement(2, Direction.UP_RIGHT) + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); Position from = Position.valueOf(5, 3); From bab88e797569685938d3b9436288957088ea11dc Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 22:53:28 +0900 Subject: [PATCH 101/128] =?UTF-8?q?test:=20StepMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movement/StepMoveRuleTest.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index 0600e14e6d..62a1566df2 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -20,7 +20,7 @@ public class StepMoveRuleTest { void execute_1() { // given Map positionPieceMap = Map.of( - Position.valueOf(5, 3), new Elephant(TeamType.RED) + Position.valueOf(5, 6), new Elephant(TeamType.RED) ); Board board = new Board(positionPieceMap); List movementOrder = List.of( @@ -29,13 +29,13 @@ void execute_1() { new Movement(1, Direction.UP_RIGHT) ); MoveRule stepMoveRule = new StepMoveRule(movementOrder); - Position from = Position.valueOf(5, 3); + Position from = Position.valueOf(5, 6); // when List actual = stepMoveRule.execute(from, board); // then - List expected = List.of(Position.valueOf(3, 6)); + List expected = List.of(Position.valueOf(3, 9)); assertThat(actual).hasSameElementsAs(expected); } @@ -140,4 +140,28 @@ void execute_5() { List expected = List.of(); assertThat(actual).hasSameElementsAs(expected); } + + @Test + @DisplayName("보드판의 경계를 나가게 되어 목적지로 이동할 수 없다") + void execute_6() { + // given + Map positionPieceMap = Map.of( + Position.valueOf(5, 7), new Elephant(TeamType.RED) + ); + Board board = new Board(positionPieceMap); + List movementOrder = List.of( + new Movement(1, Direction.RIGHT), + new Movement(1, Direction.UP_RIGHT), + new Movement(1, Direction.UP_RIGHT) + ); + MoveRule stepMoveRule = new StepMoveRule(movementOrder); + Position from = Position.valueOf(5, 7); + + // when + List actual = stepMoveRule.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).hasSameElementsAs(expected); + } } From e1fe200d746fd6ed2bd3020d96cd5a7a25ad2855 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 23:29:29 +0900 Subject: [PATCH 102/128] =?UTF-8?q?test:=20CannonMoveRuleTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=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 --- .../domain/movement/CannonMoveRuleTest.java | 108 +++++++++++++++++- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java index a6f9174b88..c983effebb 100644 --- a/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java @@ -23,22 +23,120 @@ public class CannonMoveRuleTest { class Execute { @Test - @DisplayName("이동 경로에 죽일 수 없는 기물이 있는 경우") - void success() { + @DisplayName("포는 포를 잡을 수 없다") + void execute_1() { // given Map positionPieceMap = new LinkedHashMap<>(); positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); positionPieceMap.put(Position.valueOf(6, 4), new Soldier(TeamType.RED)); positionPieceMap.put(Position.valueOf(6, 7), new Cannon(TeamType.RED)); Board board = new Board(positionPieceMap); - Position from = Position.valueOf(6, 7); - MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.LEFT); + Position from = Position.valueOf(6, 2); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when List actual = moveRuleOfCannon.execute(from, board); // then - List expected = List.of(Position.valueOf(6, 3)); + List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6)); + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("포는 포를 제외한 기물을 잡을 수 있다") + void execute_2() { + // given + Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); + positionPieceMap.put(Position.valueOf(6, 4), new Soldier(TeamType.RED)); + positionPieceMap.put(Position.valueOf(6, 7), new Soldier(TeamType.RED)); + Board board = new Board(positionPieceMap); + Position from = Position.valueOf(6, 2); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); + + // when + List actual = moveRuleOfCannon.execute(from, board); + + // then + List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6), Position.valueOf(6, 7)); + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("포는 포를 뛰어넘을 수 없다") + void execute_3() { + // given + Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); + positionPieceMap.put(Position.valueOf(6, 4), new Cannon(TeamType.RED)); + positionPieceMap.put(Position.valueOf(6, 7), new Soldier(TeamType.RED)); + Board board = new Board(positionPieceMap); + Position from = Position.valueOf(6, 2); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); + + // when + List actual = moveRuleOfCannon.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("포는 뛰어넘을 수 있는 기물이 없다면 움직일 수 없다") + void execute_4() { + // given + Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); + Board board = new Board(positionPieceMap); + Position from = Position.valueOf(6, 2); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); + + // when + List actual = moveRuleOfCannon.execute(from, board); + + // then + List expected = List.of(); + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("포는 반드시 기물을 하나 뛰어넘은 후 장애물을 만나기 전까지 이동할 수 있다") + void execute_5() { + // given + Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); + positionPieceMap.put(Position.valueOf(6, 4), new Soldier(TeamType.RED)); + positionPieceMap.put(Position.valueOf(6, 7), new Soldier(TeamType.BLUE)); + Board board = new Board(positionPieceMap); + Position from = Position.valueOf(6, 2); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); + + // when + List actual = moveRuleOfCannon.execute(from, board); + + // then + List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6)); + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("포는 반드시 기물을 하나 뛰어넘은 후 장기판의 경계까지 이동할 수 있다") + void execute_6() { + // given + Map positionPieceMap = new LinkedHashMap<>(); + positionPieceMap.put(Position.valueOf(6, 2), new Cannon(TeamType.BLUE)); + positionPieceMap.put(Position.valueOf(6, 4), new Soldier(TeamType.RED)); + Board board = new Board(positionPieceMap); + Position from = Position.valueOf(6, 2); + MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); + + // when + List actual = moveRuleOfCannon.execute(from, board); + + // then + List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6), Position.valueOf(6, 7), + Position.valueOf(6, 8), Position.valueOf(6, 9)); assertThat(actual).isEqualTo(expected); } } From a96700a24da2cb06d357dd3079b9f21422fee8d4 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Thu, 2 Apr 2026 23:44:09 +0900 Subject: [PATCH 103/128] =?UTF-8?q?test:=20TurnManagerTest=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 --- .../janggi/domain/team/TurnManagerTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/test/java/janggi/domain/team/TurnManagerTest.java diff --git a/src/test/java/janggi/domain/team/TurnManagerTest.java b/src/test/java/janggi/domain/team/TurnManagerTest.java new file mode 100644 index 0000000000..1172404f20 --- /dev/null +++ b/src/test/java/janggi/domain/team/TurnManagerTest.java @@ -0,0 +1,41 @@ +package janggi.domain.team; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class TurnManagerTest { + private TurnManager turnManager; + + @BeforeEach + void setUp() { + turnManager = new TurnManager(); + } + + @Nested + @DisplayName("턴 변경 테스트") + class ChangeTurn { + @Test + @DisplayName("처음 턴을 변경하면 초깃값(RED)에서 BLUE로 바뀐다") + void changeTurn_ToBlue() { + // when + turnManager.changeTurn(); + + // then + assertThat(turnManager.isCurrentTurnOf(TeamType.BLUE)).isTrue(); + } + + @Test + @DisplayName("한번 더 변경하면 BLUE에서 RED로 바뀐다") + void changeTurn_BackToRed() { + // when + turnManager.changeTurn(); + + // then + assertThat(turnManager.isCurrentTurnOf(TeamType.BLUE)).isTrue(); + } + } +} From 022322fa122962e1677f81cd2935bd03212e7d57 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 13:35:05 +0900 Subject: [PATCH 104/128] =?UTF-8?q?test:=20ElephantTest=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=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 --- src/test/java/janggi/domain/piece/ElephantTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/janggi/domain/piece/ElephantTest.java b/src/test/java/janggi/domain/piece/ElephantTest.java index 6442b9cebe..9b6aea2a13 100644 --- a/src/test/java/janggi/domain/piece/ElephantTest.java +++ b/src/test/java/janggi/domain/piece/ElephantTest.java @@ -81,6 +81,19 @@ void test2() { @Test @DisplayName("상은 장기판 밖으로 이동할 수 없다.") void test3() { + positionPieceMap.put(Position.valueOf(5, 2), elephant); + List expected = List.of(Position.valueOf(3, 5), Position.valueOf(2, 4), Position.valueOf(7, 5), + Position.valueOf(8, 4)); + + Board board = new Board(positionPieceMap); + List actual = elephant.calculateMovablePositions(Position.valueOf(5, 2), board); + + assertThat(actual).hasSameElementsAs(expected); + } + + @Test + @DisplayName("상은 장기판 밖으로 이동할 수 없다.") + void test4() { positionPieceMap.put(Position.valueOf(1, 1), elephant); positionPieceMap.put(Position.valueOf(1, 2), ally1); positionPieceMap.put(Position.valueOf(2, 1), ally3); From f379b99a67602c0084c8a28b86b9df4fc82ed823 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 14:06:34 +0900 Subject: [PATCH 105/128] =?UTF-8?q?refactor:=20StepMoveRule=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20=EC=83=81,=EB=A7=88?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EA=B0=80?= =?UTF-8?q?=EB=8F=85=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/movement/StepMoveRule.java | 15 +++++++ .../java/janggi/domain/piece/Elephant.java | 43 ++++--------------- src/main/java/janggi/domain/piece/Horse.java | 35 ++++----------- 3 files changed, 31 insertions(+), 62 deletions(-) diff --git a/src/main/java/janggi/domain/movement/StepMoveRule.java b/src/main/java/janggi/domain/movement/StepMoveRule.java index 50599a42a0..b46da298e3 100644 --- a/src/main/java/janggi/domain/movement/StepMoveRule.java +++ b/src/main/java/janggi/domain/movement/StepMoveRule.java @@ -13,6 +13,21 @@ public StepMoveRule(final List movementOrder) { this.movementOrder = movementOrder; } + public static StepMoveRule elephantShape(Direction straight, Direction diagonal) { + return new StepMoveRule(List.of( + new Movement(1, straight), + new Movement(1, diagonal), + new Movement(1, diagonal) + )); + } + + public static StepMoveRule horseShape(Direction straight, Direction diagonal) { + return new StepMoveRule(List.of( + new Movement(1, straight), + new Movement(1, diagonal) + )); + } + @Override public List execute(Position from, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 4451fcbc9c..ad71bf1fed 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -4,7 +4,6 @@ import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; -import janggi.domain.movement.Movement; import janggi.domain.movement.StepMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -16,40 +15,14 @@ public class Elephant implements Piece { static { final List movementStrategies = List.of( - new StepMoveRule(List.of( - new Movement(1, Direction.RIGHT), - new Movement(1, Direction.UP_RIGHT), - new Movement(1, Direction.UP_RIGHT))), - new StepMoveRule(List.of( - new Movement(1, Direction.RIGHT), - new Movement(1, Direction.DOWN_RIGHT), - new Movement(1, Direction.DOWN_RIGHT))), - new StepMoveRule(List.of( - new Movement(1, Direction.UP), - new Movement(1, Direction.UP_RIGHT), - new Movement(1, Direction.UP_RIGHT))), - new StepMoveRule(List.of( - new Movement(1, Direction.UP), - new Movement(1, Direction.UP_LEFT), - new Movement(1, Direction.UP_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.LEFT), - new Movement(1, Direction.UP_LEFT), - new Movement(1, Direction.UP_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.LEFT), - new Movement(1, Direction.DOWN_LEFT), - new Movement(1, Direction.DOWN_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.DOWN), - new Movement(1, Direction.DOWN_LEFT), - new Movement(1, Direction.DOWN_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.DOWN), - new Movement(1, Direction.DOWN_RIGHT), - new Movement(1, Direction.DOWN_RIGHT))) - ); - + StepMoveRule.elephantShape(Direction.UP, Direction.UP_LEFT), + StepMoveRule.elephantShape(Direction.UP, Direction.UP_RIGHT), + StepMoveRule.elephantShape(Direction.RIGHT, Direction.UP_RIGHT), + StepMoveRule.elephantShape(Direction.RIGHT, Direction.DOWN_RIGHT), + StepMoveRule.elephantShape(Direction.DOWN, Direction.DOWN_LEFT), + StepMoveRule.elephantShape(Direction.DOWN, Direction.DOWN_RIGHT), + StepMoveRule.elephantShape(Direction.LEFT, Direction.DOWN_LEFT), + StepMoveRule.elephantShape(Direction.LEFT, Direction.UP_LEFT)); PIECE_ACTION = new PieceAction(movementStrategies); } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index f97361b33b..81f6819a5b 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -4,7 +4,6 @@ import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; -import janggi.domain.movement.Movement; import janggi.domain.movement.StepMoveRule; import janggi.domain.team.TeamType; import java.util.List; @@ -16,32 +15,14 @@ public class Horse implements Piece { static { final List movementStrategies = List.of( - new StepMoveRule(List.of( - new Movement(1, Direction.RIGHT), - new Movement(1, Direction.UP_RIGHT))), - new StepMoveRule(List.of( - new Movement(1, Direction.RIGHT), - new Movement(1, Direction.DOWN_RIGHT))), - new StepMoveRule(List.of( - new Movement(1, Direction.UP), - new Movement(1, Direction.UP_RIGHT))), - new StepMoveRule(List.of( - new Movement(1, Direction.UP), - new Movement(1, Direction.UP_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.LEFT), - new Movement(1, Direction.UP_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.LEFT), - new Movement(1, Direction.DOWN_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.DOWN), - new Movement(1, Direction.DOWN_LEFT))), - new StepMoveRule(List.of( - new Movement(1, Direction.DOWN), - new Movement(1, Direction.DOWN_RIGHT))) - ); - + StepMoveRule.horseShape(Direction.UP, Direction.UP_LEFT), + StepMoveRule.horseShape(Direction.UP, Direction.UP_RIGHT), + StepMoveRule.horseShape(Direction.RIGHT, Direction.UP_RIGHT), + StepMoveRule.horseShape(Direction.RIGHT, Direction.DOWN_RIGHT), + StepMoveRule.horseShape(Direction.DOWN, Direction.DOWN_LEFT), + StepMoveRule.horseShape(Direction.DOWN, Direction.DOWN_RIGHT), + StepMoveRule.horseShape(Direction.LEFT, Direction.DOWN_LEFT), + StepMoveRule.horseShape(Direction.LEFT, Direction.UP_LEFT)); PIECE_ACTION = new PieceAction(movementStrategies); } From 6dc67b5967d8202d98cd132db955a07e3258e99c Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 14:25:48 +0900 Subject: [PATCH 106/128] =?UTF-8?q?refactor:=20Board=EC=9D=98=20=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=EC=A2=85=EB=A3=8C=EC=A1=B0=EA=B1=B4=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GamaManager 클래스 생성 --- .../java/janggi/controller/JanggiController.java | 11 ++++++++--- src/main/java/janggi/domain/GameManager.java | 11 +++++++++++ src/main/java/janggi/domain/board/Board.java | 15 +++++++-------- .../java/janggi/domain/board/BoardMediator.java | 3 +++ src/main/java/janggi/domain/team/TurnManager.java | 6 +++++- 5 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 src/main/java/janggi/domain/GameManager.java diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 2c5120a271..149fc159c9 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -1,5 +1,6 @@ package janggi.controller; +import janggi.domain.GameManager; import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; @@ -18,16 +19,20 @@ import java.util.List; public class JanggiController { + + private final GameManager gameManager; + public JanggiController() { + gameManager = new GameManager(); } public void run() { Board board = BoardGenerator.generate(setupRedTeam(), setupBlueTeam()); TurnManager turnManager = new TurnManager(); - while (board.hasTwoGeneral()) { + while (gameManager.isGeneralAlive(turnManager.currentTeamType(), board)) { playTurn(board, turnManager); } - OutputView.printGameOverMessage(turnManager.currentTeamType()); + OutputView.printGameOverMessage(turnManager.currentTeamTypeToString()); } private Team setupRedTeam() { @@ -50,7 +55,7 @@ private SetupStrategy readSetupCommand() { } private void playTurn(Board board, TurnManager turnManager) { - OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamType()); + OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamTypeToString()); Position from = findFromPosition(board, turnManager); Piece piece = board.getPieceInPosition(from); List movable = piece.calculateMovablePositions(from, board); diff --git a/src/main/java/janggi/domain/GameManager.java b/src/main/java/janggi/domain/GameManager.java new file mode 100644 index 0000000000..2bd6159290 --- /dev/null +++ b/src/main/java/janggi/domain/GameManager.java @@ -0,0 +1,11 @@ +package janggi.domain; + +import janggi.domain.board.BoardMediator; +import janggi.domain.team.TeamType; + +public class GameManager { + + public boolean isGeneralAlive(TeamType teamType, BoardMediator boardMediator) { + return boardMediator.hasGeneral(teamType); + } +} diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 0da66a622d..e3d10499a2 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; +import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.Map; @@ -28,18 +29,16 @@ public Piece getPieceInPosition(final Position position) { return findPieceByPosition(position); } - public Map getPositionPieceMapForDTO() { - return Map.copyOf(positionPieceMap); + @Override + public boolean hasGeneral(TeamType teamType) { + return positionPieceMap.values().stream() + .anyMatch(piece -> piece.getPieceType() == PieceType.GENERAL && piece.getTeamType() == teamType); } - public boolean hasTwoGeneral() { - long generalCount = positionPieceMap.values().stream() - .filter(piece -> piece.getPieceType() == PieceType.GENERAL) - .count(); - return generalCount == 2; + public Map getPositionPieceMapForDTO() { + return Map.copyOf(positionPieceMap); } - private boolean hasPieceIn(final Position position) { return positionPieceMap.containsKey(position); } diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java index 0756effaae..80d6f25d5c 100644 --- a/src/main/java/janggi/domain/board/BoardMediator.java +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -2,9 +2,12 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; public interface BoardMediator { boolean hasPieceAt(Position position); + boolean hasGeneral(TeamType teamType); + Piece getPieceInPosition(Position position); } diff --git a/src/main/java/janggi/domain/team/TurnManager.java b/src/main/java/janggi/domain/team/TurnManager.java index dc626c6965..477f46dd65 100644 --- a/src/main/java/janggi/domain/team/TurnManager.java +++ b/src/main/java/janggi/domain/team/TurnManager.java @@ -15,7 +15,11 @@ public boolean isCurrentTurnOf(TeamType teamType) { return this.currentTurnTeamType == teamType; } - public String currentTeamType() { + public TeamType currentTeamType() { + return currentTurnTeamType; + } + + public String currentTeamTypeToString() { return currentTurnTeamType.getName(); } } From 0eae99a6ba6ca196c495bb83ef2280e1b794cf66 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 15:24:50 +0900 Subject: [PATCH 107/128] =?UTF-8?q?test:=20=EC=A2=85=EB=A3=8C=EC=B1=85?= =?UTF-8?q?=EC=9E=84=EB=B6=84=EB=A6=AC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/board/BoardTest.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/test/java/janggi/domain/board/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java index d3b2d0e5fe..32bbeacffc 100644 --- a/src/test/java/janggi/domain/board/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -3,11 +3,13 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.GameManager; import janggi.domain.Position; import janggi.domain.piece.Cannon; import janggi.domain.piece.General; import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; +import janggi.domain.team.TurnManager; import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName; @@ -17,33 +19,33 @@ public class BoardTest { @Test - @DisplayName("보드에 왕이 2개 경우") + @DisplayName("현재 차례 플레이어의 장이 살아있다") void generalIsTwo() { - Map positionPieceMap = Map.of(); + Map positionPieceMap; Position position1 = Position.valueOf(9, 5); - Position position2 = Position.valueOf(2, 5); - positionPieceMap = Map.of( - position1, new General(TeamType.BLUE), - position2, new General(TeamType.RED)); + TurnManager turnManager = new TurnManager(); + positionPieceMap = Map.of(position1, new General(TeamType.RED)); Board board = new Board(positionPieceMap); boolean expected = true; - boolean actual = board.hasTwoGeneral(); + GameManager gameManager = new GameManager(); + boolean actual = gameManager.isGeneralAlive(turnManager.currentTeamType(), board); assertThat(actual).isEqualTo(expected); } @Test - @DisplayName("보드에 왕이 2개 미만인 경우") + @DisplayName("현재 차례 플레이어의 장이 없다") void generalIsOne() { - Map positionPieceMap = Map.of(); + Map positionPieceMap; Position position1 = Position.valueOf(9, 5); - positionPieceMap = Map.of( - position1, new General(TeamType.BLUE)); + TurnManager turnManager = new TurnManager(); + positionPieceMap = Map.of(position1, new General(TeamType.BLUE)); Board board = new Board(positionPieceMap); boolean expected = false; - boolean actual = board.hasTwoGeneral(); + GameManager gameManager = new GameManager(); + boolean actual = gameManager.isGeneralAlive(turnManager.currentTeamType(), board); assertThat(actual).isEqualTo(expected); } From b93a0f1b7e60601f097b7c1a58e6f64eff5837b6 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 15:42:45 +0900 Subject: [PATCH 108/128] =?UTF-8?q?refactor:=20CannonMoveRule=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=BA=A1=EC=8A=90=ED=99=94=20=EC=9C=84=EB=B0=98=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/janggi/domain/board/Board.java | 5 +++++ src/main/java/janggi/domain/board/BoardMediator.java | 2 ++ src/main/java/janggi/domain/movement/CannonMoveRule.java | 4 +--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index e3d10499a2..cf5987bb64 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -35,6 +35,11 @@ public boolean hasGeneral(TeamType teamType) { .anyMatch(piece -> piece.getPieceType() == PieceType.GENERAL && piece.getTeamType() == teamType); } + @Override + public boolean isCannon(Position position) { + return findPieceByPosition(position).getPieceType() == PieceType.CANNON; + } + public Map getPositionPieceMapForDTO() { return Map.copyOf(positionPieceMap); } diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java index 80d6f25d5c..8bdf0cbadc 100644 --- a/src/main/java/janggi/domain/board/BoardMediator.java +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -10,4 +10,6 @@ public interface BoardMediator { boolean hasGeneral(TeamType teamType); Piece getPieceInPosition(Position position); + + boolean isCannon(Position position); } diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index 9390143b75..bf6679a941 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -5,7 +5,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; -import janggi.domain.piece.PieceType; import java.util.ArrayList; import java.util.List; @@ -29,7 +28,6 @@ public List execute(Position from, final BoardMediator boardMediator) // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) private boolean isInvalidBridge(final Position bridge, final BoardMediator boardMediator) { - return !boardMediator.hasPieceAt(bridge) - || boardMediator.getPieceInPosition(bridge).getPieceType() == PieceType.CANNON; + return !boardMediator.hasPieceAt(bridge) || boardMediator.isCannon(bridge); } } From ed1a43f8df152483ac5274286c631f652c4c07fb Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 16:21:20 +0900 Subject: [PATCH 109/128] =?UTF-8?q?refactor:=20=EC=93=B0=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EB=A7=A4=EA=B0=9C=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/movement/CannonMoveRule.java | 2 +- src/main/java/janggi/domain/movement/Movement.java | 2 +- src/main/java/janggi/domain/movement/StepMoveRule.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index bf6679a941..5150d1b54f 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -19,7 +19,7 @@ public CannonMoveRule(final Direction direction) { @Override public List execute(Position from, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); - from = movement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); // 포다리 찾기 + from = movement.findFirstOccupiedPositionOrMax(from, boardMediator); // 포다리 찾기 if (isInvalidBridge(from, boardMediator)) { return List.of(); } diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 8d6c93d452..541ef0f36c 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -64,7 +64,7 @@ public Position calculateDestination(final Position from, final Piece piece, fin } // 처음 만나는 기물 위치 반환, 만약 끝까지 가도 없으면 그 끝 위치 반환 - public Position findFirstOccupiedPositionOrMax(final Position from, final Piece piece, + public Position findFirstOccupiedPositionOrMax(final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { final Position to = calculateNextPosition(from, distance); diff --git a/src/main/java/janggi/domain/movement/StepMoveRule.java b/src/main/java/janggi/domain/movement/StepMoveRule.java index b46da298e3..1d407db130 100644 --- a/src/main/java/janggi/domain/movement/StepMoveRule.java +++ b/src/main/java/janggi/domain/movement/StepMoveRule.java @@ -46,7 +46,7 @@ private List findLastPosition(final Position from, final Piece piece, if (!lastMovement.canMove(from) || !lastMovement.hasReachablePosition(piece, from, boardMediator)) { return List.of(); } - final Position destination = lastMovement.findFirstOccupiedPositionOrMax(from, piece, boardMediator); + final Position destination = lastMovement.findFirstOccupiedPositionOrMax(from, boardMediator); return List.of(destination); } } From 299a565ac97b5e0c291cb79721c30ed2a57a7b5c Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:02:42 +0900 Subject: [PATCH 110/128] =?UTF-8?q?refactor:=20MoveRule=EC=97=90=20TeamTyp?= =?UTF-8?q?e=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=EC=9D=98=20?= =?UTF-8?q?=EB=B3=B4=EB=93=9C=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EA=B0=90?= =?UTF-8?q?=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Board.java | 6 ++++++ .../java/janggi/domain/board/BoardMediator.java | 2 ++ .../janggi/domain/movement/CannonMoveRule.java | 5 +++-- .../java/janggi/domain/movement/MoveRule.java | 3 ++- .../java/janggi/domain/movement/Movement.java | 17 +++++++++-------- .../janggi/domain/movement/SlidingMoveRule.java | 5 +++-- .../janggi/domain/movement/StepMoveRule.java | 5 +++-- src/main/java/janggi/domain/piece/Cannon.java | 2 +- src/main/java/janggi/domain/piece/Chariot.java | 2 +- src/main/java/janggi/domain/piece/Elephant.java | 2 +- src/main/java/janggi/domain/piece/General.java | 2 +- src/main/java/janggi/domain/piece/Guard.java | 2 +- src/main/java/janggi/domain/piece/Horse.java | 2 +- .../java/janggi/domain/piece/PieceAction.java | 6 ++++-- src/main/java/janggi/domain/piece/Soldier.java | 4 ++-- .../domain/movement/CannonMoveRuleTest.java | 12 ++++++------ .../janggi/domain/movement/MovementTest.java | 13 +++++++------ .../domain/movement/SlidingMoveRuleTest.java | 8 ++++---- .../domain/movement/StepMoveRuleTest.java | 12 ++++++------ 19 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index cf5987bb64..2a3fbda94c 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -40,6 +40,12 @@ public boolean isCannon(Position position) { return findPieceByPosition(position).getPieceType() == PieceType.CANNON; } + @Override + public boolean isSameTeamType(Position position, TeamType teamType) { + Piece piece = findPieceByPosition(position); + return piece.getTeamType() == teamType; + } + public Map getPositionPieceMapForDTO() { return Map.copyOf(positionPieceMap); } diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java index 8bdf0cbadc..90cf046c40 100644 --- a/src/main/java/janggi/domain/board/BoardMediator.java +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -12,4 +12,6 @@ public interface BoardMediator { Piece getPieceInPosition(Position position); boolean isCannon(Position position); + + boolean isSameTeamType(Position position, TeamType teamType); } diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index 5150d1b54f..0f7e2de8cb 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -5,6 +5,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; import java.util.ArrayList; import java.util.List; @@ -17,13 +18,13 @@ public CannonMoveRule(final Direction direction) { } @Override - public List execute(Position from, final BoardMediator boardMediator) { + public List execute(Position from, final TeamType teamType, BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); from = movement.findFirstOccupiedPositionOrMax(from, boardMediator); // 포다리 찾기 if (isInvalidBridge(from, boardMediator)) { return List.of(); } - return new ArrayList<>(movement.calculateTraces(from, piece, boardMediator)); + return new ArrayList<>(movement.calculateTraces(from, piece, teamType, boardMediator)); } // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) diff --git a/src/main/java/janggi/domain/movement/MoveRule.java b/src/main/java/janggi/domain/movement/MoveRule.java index a1209e12cf..cee4999639 100644 --- a/src/main/java/janggi/domain/movement/MoveRule.java +++ b/src/main/java/janggi/domain/movement/MoveRule.java @@ -2,8 +2,9 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; +import janggi.domain.team.TeamType; import java.util.List; public interface MoveRule { - List execute(Position from, BoardMediator boardMediator); + List execute(Position from, TeamType teamType, BoardMediator boardMediator); } diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 541ef0f36c..3374c82649 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; import java.util.ArrayList; import java.util.List; @@ -25,11 +26,10 @@ public boolean canMove(final Position from) { public boolean hasReachablePosition(final Piece me, final Position from, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { final Position to = calculateNextPosition(from, distance); - if (!hasPieceAt(to, boardMediator)) { + if (!hasPieceAt(calculateNextPosition(from, distance), boardMediator)) { return true; } - final Piece target = findPieceAt(to, boardMediator); - if (me.canKill(target)) { + if (me.canKill(findPieceAt(to, boardMediator))) { return true; } } @@ -48,14 +48,14 @@ public boolean isBlocked(final Position from, final BoardMediator boardMediator) } // 처음 만나는 기물 찾기(그 기물이 적군이라면 기물의 위치 반환, 아군이라면 이전 위치 반환) - public Position calculateDestination(final Position from, final Piece piece, final BoardMediator boardMediator) { + public Position calculateDestination(final Position from, final TeamType teamType, + final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { final Position to = calculateNextPosition(from, distance); if (!hasPieceAt(to, boardMediator)) { continue; } - final Piece target = findPieceAt(to, boardMediator); - if (target.belongsToTeam(piece.getTeamType())) { + if (boardMediator.isSameTeamType(to, teamType)) { return calculateNextPosition(from, distance - 1); } return to; @@ -77,7 +77,8 @@ public Position findFirstOccupiedPositionOrMax(final Position from, // 이동 가능한 경로의 자취 위치 리스트를 반환한다. // 경로에 장애물을 만나면 그때까지의 리스트를 반환하고, 적을 만난다면 적의 좌표를 포함하여 반환한다. - public List calculateTraces(final Position from, final Piece piece, final BoardMediator boardMediator) { + public List calculateTraces(final Position from, final Piece piece, final TeamType teamType, + final BoardMediator boardMediator) { final List traces = new ArrayList<>(); Position prev = from; for (int distance = 1; distance <= maxDistance; distance++) { @@ -91,7 +92,7 @@ public List calculateTraces(final Position from, final Piece piece, fi continue; } final Piece target = findPieceAt(to, boardMediator); - if (!target.belongsToTeam(piece.getTeamType()) && piece.canKill(target)) { + if (!boardMediator.isSameTeamType(to, teamType) && piece.canKill(target)) { traces.add(to); } return traces; diff --git a/src/main/java/janggi/domain/movement/SlidingMoveRule.java b/src/main/java/janggi/domain/movement/SlidingMoveRule.java index 3d3b9c2e0c..8903792ecf 100644 --- a/src/main/java/janggi/domain/movement/SlidingMoveRule.java +++ b/src/main/java/janggi/domain/movement/SlidingMoveRule.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; import java.util.List; public class SlidingMoveRule implements MoveRule { @@ -14,8 +15,8 @@ public SlidingMoveRule(Movement movementOrder) { } @Override - public List execute(Position from, final BoardMediator boardMediator) { + public List execute(Position from, final TeamType teamType, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); - return movementOrder.calculateTraces(from, piece, boardMediator); + return movementOrder.calculateTraces(from, piece, teamType, boardMediator); } } diff --git a/src/main/java/janggi/domain/movement/StepMoveRule.java b/src/main/java/janggi/domain/movement/StepMoveRule.java index 1d407db130..16aa62df44 100644 --- a/src/main/java/janggi/domain/movement/StepMoveRule.java +++ b/src/main/java/janggi/domain/movement/StepMoveRule.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.piece.Piece; +import janggi.domain.team.TeamType; import java.util.List; public class StepMoveRule implements MoveRule { @@ -29,14 +30,14 @@ public static StepMoveRule horseShape(Direction straight, Direction diagonal) { } @Override - public List execute(Position from, final BoardMediator boardMediator) { + public List execute(Position from, final TeamType teamType, final BoardMediator boardMediator) { final Piece piece = boardMediator.getPieceInPosition(from); for (int index = 0; index < movementOrder.size() - 1; index++) { final Movement movement = movementOrder.get(index); if (!movement.canMove(from) || movement.isBlocked(from, boardMediator)) { return List.of(); } - from = movement.calculateDestination(from, piece, boardMediator); + from = movement.calculateDestination(from, teamType, boardMediator); } return findLastPosition(from, piece, boardMediator); } diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 06e869a6ec..527ccc3dcd 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -45,7 +45,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 2fefafcebc..e6e44dc728 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -49,7 +49,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index ad71bf1fed..ecfa9c8540 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -50,7 +50,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 2e28560a01..6617e068a6 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -50,7 +50,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 4a12475cf3..a1ed6d342b 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -50,7 +50,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 81f6819a5b..dff90395f6 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -49,7 +49,7 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/main/java/janggi/domain/piece/PieceAction.java b/src/main/java/janggi/domain/piece/PieceAction.java index 78a2ea6efe..47d5590e59 100644 --- a/src/main/java/janggi/domain/piece/PieceAction.java +++ b/src/main/java/janggi/domain/piece/PieceAction.java @@ -3,6 +3,7 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.movement.MoveRule; +import janggi.domain.team.TeamType; import java.util.Collection; import java.util.List; @@ -13,9 +14,10 @@ public PieceAction(List movementStrategies) { this.movementStrategies = List.copyOf(movementStrategies); } - public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + public List calculateMovablePositions(final Position from, final TeamType teamType, + final BoardMediator boardMediator) { return movementStrategies.stream() - .map(rule -> rule.execute(from, boardMediator)) + .map(rule -> rule.execute(from, teamType, boardMediator)) .flatMap(Collection::stream) .toList(); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index ae4df180f5..19faccf14d 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -52,9 +52,9 @@ public boolean belongsToTeam(final TeamType teamType) { @Override public List calculateMovablePositions(Position from, BoardMediator boardMediator) { if (teamType == TeamType.RED) { - return RED_PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return RED_PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - return BLUE_PIECE_ACTION.calculateMovablePositions(from, boardMediator); + return BLUE_PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override diff --git a/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java index c983effebb..8c620ed169 100644 --- a/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/CannonMoveRuleTest.java @@ -35,7 +35,7 @@ void execute_1() { MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when - List actual = moveRuleOfCannon.execute(from, board); + List actual = moveRuleOfCannon.execute(from, TeamType.BLUE, board); // then List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6)); @@ -55,7 +55,7 @@ void execute_2() { MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when - List actual = moveRuleOfCannon.execute(from, board); + List actual = moveRuleOfCannon.execute(from, TeamType.BLUE, board); // then List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6), Position.valueOf(6, 7)); @@ -75,7 +75,7 @@ void execute_3() { MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when - List actual = moveRuleOfCannon.execute(from, board); + List actual = moveRuleOfCannon.execute(from, TeamType.BLUE, board); // then List expected = List.of(); @@ -93,7 +93,7 @@ void execute_4() { MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when - List actual = moveRuleOfCannon.execute(from, board); + List actual = moveRuleOfCannon.execute(from, TeamType.BLUE, board); // then List expected = List.of(); @@ -113,7 +113,7 @@ void execute_5() { MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when - List actual = moveRuleOfCannon.execute(from, board); + List actual = moveRuleOfCannon.execute(from, TeamType.BLUE, board); // then List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6)); @@ -132,7 +132,7 @@ void execute_6() { MoveRule moveRuleOfCannon = new CannonMoveRule(Direction.RIGHT); // when - List actual = moveRuleOfCannon.execute(from, board); + List actual = moveRuleOfCannon.execute(from, TeamType.BLUE, board); // then List expected = List.of(Position.valueOf(6, 5), Position.valueOf(6, 6), Position.valueOf(6, 7), diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index c76ce49364..570327e25a 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -159,7 +159,7 @@ void success_1() { Position expected = Position.valueOf(5, 5); // when - Position actual = Movement.calculateDestination(from, board.getPieceInPosition(from), board); + Position actual = Movement.calculateDestination(from, TeamType.RED, board); // then assertThat(actual).isEqualTo(expected); @@ -178,7 +178,7 @@ void success_2() { Position expected = Position.valueOf(5, 6); // when - Position actual = Movement.calculateDestination(from, board.getPieceInPosition(from), board); + Position actual = Movement.calculateDestination(from, TeamType.RED, board); // then assertThat(actual).isEqualTo(expected); @@ -196,7 +196,7 @@ void success_3() { Position expected = Position.valueOf(5, 7); // when - Position actual = Movement.calculateDestination(from, board.getPieceInPosition(from), board); + Position actual = Movement.calculateDestination(from, TeamType.RED, board); // then assertThat(actual).isEqualTo(expected); @@ -229,7 +229,8 @@ void success_1() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); // when - List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), board); + List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), TeamType.RED, + board); // then assertThat(actual).hasSameElementsAs(expected); @@ -249,7 +250,7 @@ void success_2() { Position.valueOf(5, 6)); // when - List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), board); + List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), TeamType.RED, board); // then assertThat(actual).hasSameElementsAs(expected); @@ -268,7 +269,7 @@ void success_3() { Position.valueOf(5, 6), Position.valueOf(5, 7)); // when - List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), board); + List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), TeamType.RED, board); // then assertThat(actual).hasSameElementsAs(expected); diff --git a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java index 27c0c99475..045bc04339 100644 --- a/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/SlidingMoveRuleTest.java @@ -31,7 +31,7 @@ public void success1() { Position from = Position.valueOf(5, 3); // when - List actual = moveRuleWithTraces.execute(from, board); + List actual = moveRuleWithTraces.execute(from, TeamType.RED, board); // then List expected = List.of( @@ -56,7 +56,7 @@ public void success2() { Position from = Position.valueOf(5, 3); // when - List actual = moveRuleWithTraces.execute(from, board); + List actual = moveRuleWithTraces.execute(from, TeamType.RED, board); // then List expected = List.of( @@ -77,7 +77,7 @@ public void success3() { Position from = Position.valueOf(5, 3); // when - List actual = moveRuleWithTraces.execute(from, board); + List actual = moveRuleWithTraces.execute(from, TeamType.RED, board); // then List expected = List.of( @@ -100,7 +100,7 @@ public void success4() { Position from = Position.valueOf(1, 3); // when - List actual = moveRuleWithTraces.execute(from, board); + List actual = moveRuleWithTraces.execute(from, TeamType.RED, board); // then List expected = List.of(); diff --git a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java index 62a1566df2..0935bd4eb0 100644 --- a/src/test/java/janggi/domain/movement/StepMoveRuleTest.java +++ b/src/test/java/janggi/domain/movement/StepMoveRuleTest.java @@ -32,7 +32,7 @@ void execute_1() { Position from = Position.valueOf(5, 6); // when - List actual = stepMoveRule.execute(from, board); + List actual = stepMoveRule.execute(from, TeamType.RED, board); // then List expected = List.of(Position.valueOf(3, 9)); @@ -57,7 +57,7 @@ void execute_2() { Position from = Position.valueOf(5, 3); // when - List actual = stepMoveRule.execute(from, board); + List actual = stepMoveRule.execute(from, TeamType.RED, board); // then List expected = List.of(); @@ -82,7 +82,7 @@ void execute_3() { Position from = Position.valueOf(5, 3); // when - List actual = stepMoveRule.execute(from, board); + List actual = stepMoveRule.execute(from, TeamType.RED, board); // then List expected = List.of(Position.valueOf(3, 6)); @@ -108,7 +108,7 @@ void execute_4() { Position from = Position.valueOf(5, 3); // when - List actual = stepMoveRule.execute(from, board); + List actual = stepMoveRule.execute(from, TeamType.RED, board); // then List expected = List.of(); @@ -134,7 +134,7 @@ void execute_5() { Position from = Position.valueOf(5, 3); // when - List actual = stepMoveRule.execute(from, board); + List actual = stepMoveRule.execute(from, TeamType.RED, board); // then List expected = List.of(); @@ -158,7 +158,7 @@ void execute_6() { Position from = Position.valueOf(5, 7); // when - List actual = stepMoveRule.execute(from, board); + List actual = stepMoveRule.execute(from, TeamType.RED, board); // then List expected = List.of(); From 641314f0397f09c6b359ae8bfaf155f2d4f0f4ca Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:11:23 +0900 Subject: [PATCH 111/128] =?UTF-8?q?fix:=20=EC=8A=B9=EB=A6=AC=ED=95=9C=20?= =?UTF-8?q?=EB=82=98=EB=9D=BC=EB=A1=9C=20=EC=B6=9C=EB=A0=A5=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=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/janggi/controller/JanggiController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 149fc159c9..8ab8f92be2 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -32,6 +32,7 @@ public void run() { while (gameManager.isGeneralAlive(turnManager.currentTeamType(), board)) { playTurn(board, turnManager); } + turnManager.changeTurn(); OutputView.printGameOverMessage(turnManager.currentTeamTypeToString()); } From 5ac4a06db59cbbad1fda4cb7c92520592d331101 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:31:51 +0900 Subject: [PATCH 112/128] =?UTF-8?q?refactor:=20calculateTraces=EC=97=90=20?= =?UTF-8?q?piece=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=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 --- .../java/janggi/domain/movement/CannonMoveRule.java | 4 +--- src/main/java/janggi/domain/movement/Movement.java | 13 ++++++------- .../janggi/domain/movement/SlidingMoveRule.java | 4 +--- .../java/janggi/domain/movement/StepMoveRule.java | 8 +++----- .../java/janggi/domain/movement/MovementTest.java | 12 ++++++------ 5 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index 0f7e2de8cb..bfe69933ea 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -4,7 +4,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.ArrayList; import java.util.List; @@ -19,12 +18,11 @@ public CannonMoveRule(final Direction direction) { @Override public List execute(Position from, final TeamType teamType, BoardMediator boardMediator) { - final Piece piece = boardMediator.getPieceInPosition(from); from = movement.findFirstOccupiedPositionOrMax(from, boardMediator); // 포다리 찾기 if (isInvalidBridge(from, boardMediator)) { return List.of(); } - return new ArrayList<>(movement.calculateTraces(from, piece, teamType, boardMediator)); + return new ArrayList<>(movement.calculateTraces(from, teamType, boardMediator)); } // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 3374c82649..abf3707d44 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -23,13 +23,13 @@ public boolean canMove(final Position from) { // 마지막 movement에서만 사용 // 현재 기물이 다음으로 가는 곳에서 갈 수 있는 칸이 있는지 - public boolean hasReachablePosition(final Piece me, final Position from, final BoardMediator boardMediator) { + public boolean hasReachablePosition(Position from, TeamType teamType, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { - final Position to = calculateNextPosition(from, distance); - if (!hasPieceAt(calculateNextPosition(from, distance), boardMediator)) { + from = calculateNextPosition(from, distance); + if (!hasPieceAt(from, boardMediator)) { return true; } - if (me.canKill(findPieceAt(to, boardMediator))) { + if (!boardMediator.isSameTeamType(from, teamType)) { return true; } } @@ -77,7 +77,7 @@ public Position findFirstOccupiedPositionOrMax(final Position from, // 이동 가능한 경로의 자취 위치 리스트를 반환한다. // 경로에 장애물을 만나면 그때까지의 리스트를 반환하고, 적을 만난다면 적의 좌표를 포함하여 반환한다. - public List calculateTraces(final Position from, final Piece piece, final TeamType teamType, + public List calculateTraces(final Position from, final TeamType teamType, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); Position prev = from; @@ -91,8 +91,7 @@ public List calculateTraces(final Position from, final Piece piece, fi prev = to; continue; } - final Piece target = findPieceAt(to, boardMediator); - if (!boardMediator.isSameTeamType(to, teamType) && piece.canKill(target)) { + if (!boardMediator.isSameTeamType(to, teamType)) { traces.add(to); } return traces; diff --git a/src/main/java/janggi/domain/movement/SlidingMoveRule.java b/src/main/java/janggi/domain/movement/SlidingMoveRule.java index 8903792ecf..c5c44d1dfa 100644 --- a/src/main/java/janggi/domain/movement/SlidingMoveRule.java +++ b/src/main/java/janggi/domain/movement/SlidingMoveRule.java @@ -2,7 +2,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.List; @@ -16,7 +15,6 @@ public SlidingMoveRule(Movement movementOrder) { @Override public List execute(Position from, final TeamType teamType, final BoardMediator boardMediator) { - final Piece piece = boardMediator.getPieceInPosition(from); - return movementOrder.calculateTraces(from, piece, teamType, boardMediator); + return movementOrder.calculateTraces(from, teamType, boardMediator); } } diff --git a/src/main/java/janggi/domain/movement/StepMoveRule.java b/src/main/java/janggi/domain/movement/StepMoveRule.java index 16aa62df44..45b3da255f 100644 --- a/src/main/java/janggi/domain/movement/StepMoveRule.java +++ b/src/main/java/janggi/domain/movement/StepMoveRule.java @@ -2,7 +2,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.List; @@ -31,7 +30,6 @@ public static StepMoveRule horseShape(Direction straight, Direction diagonal) { @Override public List execute(Position from, final TeamType teamType, final BoardMediator boardMediator) { - final Piece piece = boardMediator.getPieceInPosition(from); for (int index = 0; index < movementOrder.size() - 1; index++) { final Movement movement = movementOrder.get(index); if (!movement.canMove(from) || movement.isBlocked(from, boardMediator)) { @@ -39,12 +37,12 @@ public List execute(Position from, final TeamType teamType, final Boar } from = movement.calculateDestination(from, teamType, boardMediator); } - return findLastPosition(from, piece, boardMediator); + return findLastPosition(from, teamType, boardMediator); } - private List findLastPosition(final Position from, final Piece piece, final BoardMediator boardMediator) { + private List findLastPosition(final Position from, TeamType teamType, final BoardMediator boardMediator) { final Movement lastMovement = movementOrder.getLast(); - if (!lastMovement.canMove(from) || !lastMovement.hasReachablePosition(piece, from, boardMediator)) { + if (!lastMovement.canMove(from) || !lastMovement.hasReachablePosition(from, teamType, boardMediator)) { return List.of(); } final Position destination = lastMovement.findFirstOccupiedPositionOrMax(from, boardMediator); diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index 570327e25a..eb4bf4a111 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -44,7 +44,7 @@ void success_1() { boolean expected = true; // when - boolean actual = Movement.hasReachablePosition(me, from, board); + boolean actual = Movement.hasReachablePosition(from, TeamType.RED, board); // then assertThat(actual).isEqualTo(expected); @@ -61,7 +61,7 @@ void success_2() { boolean expected = false; // when - boolean actual = Movement.hasReachablePosition(me, from, board); + boolean actual = Movement.hasReachablePosition(from, TeamType.RED, board); // then assertThat(actual).isEqualTo(expected); @@ -77,7 +77,7 @@ void success_3() { boolean expected = true; // when - boolean actual = Movement.hasReachablePosition(me, from, board); + boolean actual = Movement.hasReachablePosition(from, TeamType.RED, board); // then assertThat(actual).isEqualTo(expected); @@ -229,7 +229,7 @@ void success_1() { List expected = List.of(Position.valueOf(5, 4), Position.valueOf(5, 5)); // when - List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), TeamType.RED, + List actual = Movement.calculateTraces(from, TeamType.RED, board); // then @@ -250,7 +250,7 @@ void success_2() { Position.valueOf(5, 6)); // when - List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), TeamType.RED, board); + List actual = Movement.calculateTraces(from, TeamType.RED, board); // then assertThat(actual).hasSameElementsAs(expected); @@ -269,7 +269,7 @@ void success_3() { Position.valueOf(5, 6), Position.valueOf(5, 7)); // when - List actual = Movement.calculateTraces(from, board.getPieceInPosition(from), TeamType.RED, board); + List actual = Movement.calculateTraces(from, TeamType.RED, board); // then assertThat(actual).hasSameElementsAs(expected); From e3f163e67c44106109ac616123cc0d89a8ec8f13 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:39:09 +0900 Subject: [PATCH 113/128] =?UTF-8?q?refactor:=20Movement=EC=97=90=EC=84=9C?= =?UTF-8?q?=20Piece=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/movement/Movement.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index abf3707d44..0778a85e9f 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -2,7 +2,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.ArrayList; import java.util.List; @@ -99,6 +98,30 @@ public List calculateTraces(final Position from, final TeamType teamTy return traces; } + // 이동 가능한 경로의 자취 위치 리스트를 반환한다. + // 경로에 장애물을 만나면 그때까지의 리스트를 반환하고, 적을 만난다면 적의 좌표를 포함하여 반환한다. + public List calculateTracesForCannon(final Position from, final TeamType teamType, + final BoardMediator boardMediator) { + final List traces = new ArrayList<>(); + Position prev = from; + for (int distance = 1; distance <= maxDistance; distance++) { + Position to = calculateNextPosition(from, distance); + if (prev.equals(to)) { + return traces; + } + if (!hasPieceAt(to, boardMediator)) { + traces.add(to); + prev = to; + continue; + } + if (!boardMediator.isSameTeamType(to, teamType) && !boardMediator.isCannon(to)) { + traces.add(to); + } + return traces; + } + return traces; + } + private Position calculateNextPosition(final Position from, final int distance) { return from.calculateNext(distance, direction); } @@ -106,8 +129,4 @@ private Position calculateNextPosition(final Position from, final int distance) private boolean hasPieceAt(final Position position, final BoardMediator boardMediator) { return boardMediator.hasPieceAt(position); } - - private Piece findPieceAt(final Position position, final BoardMediator boardMediator) { - return boardMediator.getPieceInPosition(position); - } } From 2cc764be38a6e0586be5e8ea9e885d970df94808 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:43:34 +0900 Subject: [PATCH 114/128] =?UTF-8?q?refactor:=20Cannon=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=20=EA=B7=9C=EC=B9=99=EC=9D=84=20CalculateTracesForCannon?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/movement/CannonMoveRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index bfe69933ea..c72bae9838 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -22,7 +22,7 @@ public List execute(Position from, final TeamType teamType, BoardMedia if (isInvalidBridge(from, boardMediator)) { return List.of(); } - return new ArrayList<>(movement.calculateTraces(from, teamType, boardMediator)); + return new ArrayList<>(movement.calculateTracesForCannon(from, teamType, boardMediator)); } // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) From b7c49c8b2bc04d2f7c19c8999b3b012ad036f3b3 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:49:17 +0900 Subject: [PATCH 115/128] =?UTF-8?q?fix:=20hasReachablePosition=EC=97=90?= =?UTF-8?q?=EC=84=9C=20from=20=EB=B3=80=EC=88=98=20=EC=9E=AC=ED=95=A0?= =?UTF-8?q?=EB=8B=B9=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EA=B3=84=EC=82=B0=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/janggi/domain/movement/Movement.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 0778a85e9f..bf5820efeb 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -22,13 +22,13 @@ public boolean canMove(final Position from) { // 마지막 movement에서만 사용 // 현재 기물이 다음으로 가는 곳에서 갈 수 있는 칸이 있는지 - public boolean hasReachablePosition(Position from, TeamType teamType, final BoardMediator boardMediator) { + public boolean hasReachablePosition(Position from, final TeamType teamType, final BoardMediator boardMediator) { for (int distance = 1; distance <= maxDistance; distance++) { - from = calculateNextPosition(from, distance); - if (!hasPieceAt(from, boardMediator)) { + Position to = calculateNextPosition(from, distance); + if (!hasPieceAt(to, boardMediator)) { return true; } - if (!boardMediator.isSameTeamType(from, teamType)) { + if (!boardMediator.isSameTeamType(to, teamType)) { return true; } } From 0bb172e194ee6407c01178af17af62ac5615e6fa Mon Sep 17 00:00:00 2001 From: mvg01 Date: Fri, 3 Apr 2026 17:52:40 +0900 Subject: [PATCH 116/128] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cannon.java | 5 ----- src/main/java/janggi/domain/piece/Chariot.java | 5 ----- src/main/java/janggi/domain/piece/Elephant.java | 5 ----- src/main/java/janggi/domain/piece/General.java | 5 ----- src/main/java/janggi/domain/piece/Guard.java | 5 ----- src/main/java/janggi/domain/piece/Horse.java | 6 ------ src/main/java/janggi/domain/piece/Piece.java | 2 -- src/main/java/janggi/domain/piece/Soldier.java | 5 ----- 8 files changed, 38 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 527ccc3dcd..bef198a4b8 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -47,9 +47,4 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !PIECE_TYPE.equals(target.getPieceType()) && !target.belongsToTeam(teamType); - } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index e6e44dc728..fdce6e612e 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -51,9 +51,4 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !target.belongsToTeam(teamType); - } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index ecfa9c8540..a7a1393f2a 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -52,9 +52,4 @@ public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !target.belongsToTeam(teamType); - } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index 6617e068a6..e0dedd2bcb 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -52,9 +52,4 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !target.belongsToTeam(teamType); - } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index a1ed6d342b..867b466b4f 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -52,9 +52,4 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !target.belongsToTeam(teamType); - } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index dff90395f6..5d2d7c4d76 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -51,10 +51,4 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !target.belongsToTeam( - teamType); - } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 9f25e3aa52..ece8c539ef 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -13,6 +13,4 @@ public interface Piece { boolean belongsToTeam(TeamType teamType); List calculateMovablePositions(Position from, BoardMediator boardMediator); - - boolean canKill(Piece target); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 19faccf14d..6c308d5d69 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -56,9 +56,4 @@ public List calculateMovablePositions(Position from, BoardMediator boa } return BLUE_PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } - - @Override - public boolean canKill(final Piece target) { - return !target.belongsToTeam(teamType); - } } From 0fbb82c985dd48f067021576d3bb0fdb893ebdc7 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 10:20:02 +0900 Subject: [PATCH 117/128] =?UTF-8?q?refactor:=20setup=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20board=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/controller/JanggiController.java | 4 ++-- .../janggi/domain/{ => board}/setup/ElephantFormation.java | 2 +- .../{ => board}/setup/InnerElephantElephantFormation.java | 2 +- .../{ => board}/setup/LeftElephantElephantFormation.java | 2 +- .../{ => board}/setup/OuterElephantElephantFormation.java | 2 +- .../{ => board}/setup/RightElephantElephantFormation.java | 2 +- .../java/janggi/domain/{ => board}/setup/SetupStrategy.java | 2 +- src/main/java/janggi/domain/team/BlueTeam.java | 2 +- src/main/java/janggi/domain/team/RedTeam.java | 2 +- src/test/java/janggi/domain/board/BoardGeneratorTest.java | 2 +- .../domain/setup/InnerElephantElephantFormationTest.java | 1 + .../domain/setup/LeftElephantElephantFormationTest.java | 1 + .../domain/setup/OuterElephantElephantFormationTest.java | 1 + .../domain/setup/RightElephantElephantFormationTest.java | 1 + 14 files changed, 15 insertions(+), 11 deletions(-) rename src/main/java/janggi/domain/{ => board}/setup/ElephantFormation.java (97%) rename src/main/java/janggi/domain/{ => board}/setup/InnerElephantElephantFormation.java (94%) rename src/main/java/janggi/domain/{ => board}/setup/LeftElephantElephantFormation.java (94%) rename src/main/java/janggi/domain/{ => board}/setup/OuterElephantElephantFormation.java (94%) rename src/main/java/janggi/domain/{ => board}/setup/RightElephantElephantFormation.java (94%) rename src/main/java/janggi/domain/{ => board}/setup/SetupStrategy.java (97%) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 8ab8f92be2..18c010b1b2 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -4,9 +4,9 @@ import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; +import janggi.domain.board.setup.ElephantFormation; +import janggi.domain.board.setup.SetupStrategy; import janggi.domain.piece.Piece; -import janggi.domain.setup.ElephantFormation; -import janggi.domain.setup.SetupStrategy; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import janggi.domain.team.Team; diff --git a/src/main/java/janggi/domain/setup/ElephantFormation.java b/src/main/java/janggi/domain/board/setup/ElephantFormation.java similarity index 97% rename from src/main/java/janggi/domain/setup/ElephantFormation.java rename to src/main/java/janggi/domain/board/setup/ElephantFormation.java index bf9271cf3c..a7fb58e62a 100644 --- a/src/main/java/janggi/domain/setup/ElephantFormation.java +++ b/src/main/java/janggi/domain/board/setup/ElephantFormation.java @@ -1,4 +1,4 @@ -package janggi.domain.setup; +package janggi.domain.board.setup; import janggi.domain.Position; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java b/src/main/java/janggi/domain/board/setup/InnerElephantElephantFormation.java similarity index 94% rename from src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java rename to src/main/java/janggi/domain/board/setup/InnerElephantElephantFormation.java index 3569254936..c4ffaaa61b 100644 --- a/src/main/java/janggi/domain/setup/InnerElephantElephantFormation.java +++ b/src/main/java/janggi/domain/board/setup/InnerElephantElephantFormation.java @@ -1,4 +1,4 @@ -package janggi.domain.setup; +package janggi.domain.board.setup; import janggi.domain.Position; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java b/src/main/java/janggi/domain/board/setup/LeftElephantElephantFormation.java similarity index 94% rename from src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java rename to src/main/java/janggi/domain/board/setup/LeftElephantElephantFormation.java index 2c45fe9b66..6852ebcd74 100644 --- a/src/main/java/janggi/domain/setup/LeftElephantElephantFormation.java +++ b/src/main/java/janggi/domain/board/setup/LeftElephantElephantFormation.java @@ -1,4 +1,4 @@ -package janggi.domain.setup; +package janggi.domain.board.setup; import janggi.domain.Position; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java b/src/main/java/janggi/domain/board/setup/OuterElephantElephantFormation.java similarity index 94% rename from src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java rename to src/main/java/janggi/domain/board/setup/OuterElephantElephantFormation.java index 5e936b26a1..81b7d7cf8c 100644 --- a/src/main/java/janggi/domain/setup/OuterElephantElephantFormation.java +++ b/src/main/java/janggi/domain/board/setup/OuterElephantElephantFormation.java @@ -1,4 +1,4 @@ -package janggi.domain.setup; +package janggi.domain.board.setup; import janggi.domain.Position; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java b/src/main/java/janggi/domain/board/setup/RightElephantElephantFormation.java similarity index 94% rename from src/main/java/janggi/domain/setup/RightElephantElephantFormation.java rename to src/main/java/janggi/domain/board/setup/RightElephantElephantFormation.java index 59eca21e98..9edc17164b 100644 --- a/src/main/java/janggi/domain/setup/RightElephantElephantFormation.java +++ b/src/main/java/janggi/domain/board/setup/RightElephantElephantFormation.java @@ -1,4 +1,4 @@ -package janggi.domain.setup; +package janggi.domain.board.setup; import janggi.domain.Position; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/domain/setup/SetupStrategy.java b/src/main/java/janggi/domain/board/setup/SetupStrategy.java similarity index 97% rename from src/main/java/janggi/domain/setup/SetupStrategy.java rename to src/main/java/janggi/domain/board/setup/SetupStrategy.java index 7659d3959c..1104d15854 100644 --- a/src/main/java/janggi/domain/setup/SetupStrategy.java +++ b/src/main/java/janggi/domain/board/setup/SetupStrategy.java @@ -1,4 +1,4 @@ -package janggi.domain.setup; +package janggi.domain.board.setup; import java.util.function.Supplier; diff --git a/src/main/java/janggi/domain/team/BlueTeam.java b/src/main/java/janggi/domain/team/BlueTeam.java index ff4c30d148..c8131e2214 100644 --- a/src/main/java/janggi/domain/team/BlueTeam.java +++ b/src/main/java/janggi/domain/team/BlueTeam.java @@ -1,9 +1,9 @@ package janggi.domain.team; import janggi.domain.Position; +import janggi.domain.board.setup.ElephantFormation; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; -import janggi.domain.setup.ElephantFormation; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/janggi/domain/team/RedTeam.java b/src/main/java/janggi/domain/team/RedTeam.java index 7c6ccf8604..fa7412884d 100644 --- a/src/main/java/janggi/domain/team/RedTeam.java +++ b/src/main/java/janggi/domain/team/RedTeam.java @@ -1,9 +1,9 @@ package janggi.domain.team; import janggi.domain.Position; +import janggi.domain.board.setup.ElephantFormation; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; -import janggi.domain.setup.ElephantFormation; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/board/BoardGeneratorTest.java b/src/test/java/janggi/domain/board/BoardGeneratorTest.java index 840241bde1..7288aa6528 100644 --- a/src/test/java/janggi/domain/board/BoardGeneratorTest.java +++ b/src/test/java/janggi/domain/board/BoardGeneratorTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.setup.InnerElephantElephantFormation; +import janggi.domain.board.setup.InnerElephantElephantFormation; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import org.assertj.core.api.InstanceOfAssertFactories; diff --git a/src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java index 121ac08c90..4d43e7bf5c 100644 --- a/src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/InnerElephantElephantFormationTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.Position; +import janggi.domain.board.setup.InnerElephantElephantFormation; import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; diff --git a/src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java index ff78f4e50c..42686856f1 100644 --- a/src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/LeftElephantElephantFormationTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.Position; +import janggi.domain.board.setup.LeftElephantElephantFormation; import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; diff --git a/src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java index eadaff1d90..c3765b5b70 100644 --- a/src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/OuterElephantElephantFormationTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.Position; +import janggi.domain.board.setup.OuterElephantElephantFormation; import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; diff --git a/src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java b/src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java index 52acc44add..4390f1a02a 100644 --- a/src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java +++ b/src/test/java/janggi/domain/setup/RightElephantElephantFormationTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.Position; +import janggi.domain.board.setup.RightElephantElephantFormation; import janggi.domain.fixture.SetupPolicyTestFixture; import janggi.domain.piece.PieceType; import java.util.LinkedHashMap; From c452a5871a8614618deca585a7a7791048ae115b Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 11:10:48 +0900 Subject: [PATCH 118/128] =?UTF-8?q?refactor:=20Board=EC=97=90=20TDA?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=81=EC=9A=A9=ED=95=B4=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Position.java | 40 +++++++++---------- src/main/java/janggi/domain/board/Board.java | 8 ++-- src/main/java/janggi/domain/piece/Cannon.java | 7 +++- .../java/janggi/domain/piece/Chariot.java | 2 +- .../java/janggi/domain/piece/Elephant.java | 2 +- .../java/janggi/domain/piece/General.java | 7 +++- src/main/java/janggi/domain/piece/Guard.java | 2 +- src/main/java/janggi/domain/piece/Horse.java | 2 +- src/main/java/janggi/domain/piece/Piece.java | 10 ++++- .../java/janggi/domain/piece/Soldier.java | 2 +- .../java/janggi/domain/piece/PieceTest.java | 4 +- 11 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 8baf1c9496..8135edbc26 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -24,20 +24,6 @@ public final class Position { private final int row; private final int column; - @Override - public boolean equals(final Object object) { - if (object == null || getClass() != object.getClass()) { - return false; - } - final Position position = (Position) object; - return row == position.row && column == position.column; - } - - @Override - public int hashCode() { - return Objects.hash(row, column); - } - private Position(final int row, final int column) { this.row = row; this.column = column; @@ -53,10 +39,6 @@ public static Position valueOf(final int row, final int column) { return secondaryMap.get(column); } - public Position flipAroundMiddleRow() { - return Position.valueOf(ROW_FLIP_VALUE - row, column); - } - private static void validateRowRange(final int row) { if (row < MINIMUM_ROW || row > MAXIMUM_ROW) { throw new IllegalArgumentException("행 입력은 1~10을 입력해야 합니다."); @@ -69,12 +51,16 @@ private static void validateColumnRange(final int column) { } } + public Position flipAroundMiddleRow() { + return Position.valueOf(ROW_FLIP_VALUE - row, column); + } + public boolean checkNextBound(final int distance, final Direction direction) { final int nextRow = row + direction.getRowDirection() * distance; final int nextColumn = column + direction.getColumnDirection() * distance; return nextRow >= MINIMUM_ROW && nextRow <= MAXIMUM_ROW && nextColumn >= MINIMUM_COLUMN - && nextColumn <= MAXIMUM_COLUMN; + && nextColumn <= MAXIMUM_COLUMN; } public Position calculateNext(final int distance, final Direction direction) { @@ -82,6 +68,20 @@ public Position calculateNext(final int distance, final Direction direction) { final int nextColumn = column + direction.getColumnDirection() * distance; return Position.valueOf(Math.clamp(nextRow, MINIMUM_ROW, MAXIMUM_ROW), - Math.clamp(nextColumn, MINIMUM_COLUMN, MAXIMUM_COLUMN)); + Math.clamp(nextColumn, MINIMUM_COLUMN, MAXIMUM_COLUMN)); + } + + @Override + public boolean equals(final Object object) { + if (object == null || getClass() != object.getClass()) { + return false; + } + final Position position = (Position) object; + return row == position.row && column == position.column; + } + + @Override + public int hashCode() { + return Objects.hash(row, column); } } diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 2a3fbda94c..def33a0eec 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -2,7 +2,6 @@ import janggi.domain.Position; import janggi.domain.piece.Piece; -import janggi.domain.piece.PieceType; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; import java.util.Map; @@ -32,18 +31,17 @@ public Piece getPieceInPosition(final Position position) { @Override public boolean hasGeneral(TeamType teamType) { return positionPieceMap.values().stream() - .anyMatch(piece -> piece.getPieceType() == PieceType.GENERAL && piece.getTeamType() == teamType); + .anyMatch(piece -> piece.isGeneral() && piece.isSameTeamType(teamType)); } @Override public boolean isCannon(Position position) { - return findPieceByPosition(position).getPieceType() == PieceType.CANNON; + return findPieceByPosition(position).isCannon(); } @Override public boolean isSameTeamType(Position position, TeamType teamType) { - Piece piece = findPieceByPosition(position); - return piece.getTeamType() == teamType; + return findPieceByPosition(position).isSameTeamType(teamType); } public Map getPositionPieceMapForDTO() { diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index bef198a4b8..ded7840fb9 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -39,7 +39,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } @@ -47,4 +47,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } + + @Override + public boolean isCannon() { + return true; + } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index fdce6e612e..370373af25 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -43,7 +43,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index a7a1393f2a..15131f4c1a 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -43,7 +43,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index e0dedd2bcb..e15587f46e 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -44,7 +44,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } @@ -52,4 +52,9 @@ public boolean belongsToTeam(final TeamType teamType) { public List calculateMovablePositions(Position from, BoardMediator boardMediator) { return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } + + @Override + public boolean isGeneral() { + return true; + } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 867b466b4f..107c11666a 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -44,7 +44,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 5d2d7c4d76..4ad3c06e3c 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -43,7 +43,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index ece8c539ef..04dd0c976c 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -10,7 +10,15 @@ public interface Piece { TeamType getTeamType(); - boolean belongsToTeam(TeamType teamType); + boolean isSameTeamType(TeamType teamType); List calculateMovablePositions(Position from, BoardMediator boardMediator); + + default boolean isGeneral() { + return false; + } + + default boolean isCannon() { + return false; + } } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 6c308d5d69..61262ff880 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -45,7 +45,7 @@ public TeamType getTeamType() { } @Override - public boolean belongsToTeam(final TeamType teamType) { + public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } diff --git a/src/test/java/janggi/domain/piece/PieceTest.java b/src/test/java/janggi/domain/piece/PieceTest.java index b2b0889b06..353bae8c3b 100644 --- a/src/test/java/janggi/domain/piece/PieceTest.java +++ b/src/test/java/janggi/domain/piece/PieceTest.java @@ -21,7 +21,7 @@ void success_1() { Piece cannon = new Cannon(teamType); boolean expected = true; - boolean actual = cannon.belongsToTeam(teamType); + boolean actual = cannon.isSameTeamType(teamType); assertThat(actual).isEqualTo(expected); } @@ -34,7 +34,7 @@ void success_2() { Piece cannon = new Cannon(otherTeamType); boolean expected = false; - boolean actual = cannon.belongsToTeam(teamType); + boolean actual = cannon.isSameTeamType(teamType); assertThat(actual).isEqualTo(expected); } From 4edb6e243bd812a1b1f8c5c03b2ea390e009bb5d Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 11:33:42 +0900 Subject: [PATCH 119/128] =?UTF-8?q?refactor:=20piece=EC=97=90=EC=84=9C=20D?= =?UTF-8?q?TO=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20getter=EB=A1=9C=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 그 외의 getter 사용처 모두 제거 --- src/main/java/janggi/domain/piece/Cannon.java | 20 +++++++++---------- .../java/janggi/domain/piece/Chariot.java | 16 +++++++-------- .../java/janggi/domain/piece/Elephant.java | 18 ++++++++--------- .../java/janggi/domain/piece/General.java | 20 +++++++++---------- src/main/java/janggi/domain/piece/Guard.java | 16 +++++++-------- src/main/java/janggi/domain/piece/Horse.java | 16 +++++++-------- src/main/java/janggi/domain/piece/Piece.java | 8 ++++---- .../java/janggi/domain/piece/Soldier.java | 20 +++++++++---------- src/main/java/janggi/dto/BoardDto.java | 4 ++-- 9 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index ded7840fb9..08c6b7eaca 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -28,16 +28,6 @@ public Cannon(final TeamType teamType) { this.teamType = teamType; } - @Override - public PieceType getPieceType() { - return PIECE_TYPE; - } - - @Override - public TeamType getTeamType() { - return teamType; - } - @Override public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; @@ -52,4 +42,14 @@ public List calculateMovablePositions(final Position from, final Board public boolean isCannon() { return true; } + + @Override + public TeamType getTeamTypeForDTO() { + return teamType; + } + + @Override + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; + } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index 370373af25..d4ede53b12 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -33,22 +33,22 @@ public Chariot(final TeamType teamType) { } @Override - public PieceType getPieceType() { - return PIECE_TYPE; + public boolean isSameTeamType(final TeamType teamType) { + return this.teamType == teamType; } @Override - public TeamType getTeamType() { - return teamType; + public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; + public TeamType getTeamTypeForDTO() { + return teamType; } @Override - public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index 15131f4c1a..e2cd3822e6 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -33,23 +33,23 @@ public Elephant(final TeamType teamType) { } @Override - public PieceType getPieceType() { - return PIECE_TYPE; + public boolean isSameTeamType(final TeamType teamType) { + return this.teamType == teamType; } @Override - public TeamType getTeamType() { - return teamType; + public List calculateMovablePositions(final Position from, + final BoardMediator boardMediator) { + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; + public TeamType getTeamTypeForDTO() { + return teamType; } @Override - public List calculateMovablePositions(final Position from, - final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; } } diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index e15587f46e..fbabc08edc 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -33,16 +33,6 @@ public General(final TeamType teamType) { this.teamType = teamType; } - @Override - public PieceType getPieceType() { - return PIECE_TYPE; - } - - @Override - public TeamType getTeamType() { - return teamType; - } - @Override public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; @@ -57,4 +47,14 @@ public List calculateMovablePositions(Position from, BoardMediator boa public boolean isGeneral() { return true; } + + @Override + public TeamType getTeamTypeForDTO() { + return teamType; + } + + @Override + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; + } } diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 107c11666a..5f8450b5c5 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -34,22 +34,22 @@ public Guard(final TeamType teamType) { } @Override - public PieceType getPieceType() { - return PIECE_TYPE; + public boolean isSameTeamType(final TeamType teamType) { + return this.teamType == teamType; } @Override - public TeamType getTeamType() { - return teamType; + public List calculateMovablePositions(Position from, BoardMediator boardMediator) { + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; + public TeamType getTeamTypeForDTO() { + return teamType; } @Override - public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; } } diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 4ad3c06e3c..9360b5cc89 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -33,22 +33,22 @@ public Horse(final TeamType teamType) { } @Override - public PieceType getPieceType() { - return PIECE_TYPE; + public boolean isSameTeamType(final TeamType teamType) { + return this.teamType == teamType; } @Override - public TeamType getTeamType() { - return teamType; + public List calculateMovablePositions(Position from, BoardMediator boardMediator) { + return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; + public TeamType getTeamTypeForDTO() { + return teamType; } @Override - public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; } } diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 04dd0c976c..9e080d258e 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -6,10 +6,6 @@ import java.util.List; public interface Piece { - PieceType getPieceType(); - - TeamType getTeamType(); - boolean isSameTeamType(TeamType teamType); List calculateMovablePositions(Position from, BoardMediator boardMediator); @@ -21,4 +17,8 @@ default boolean isGeneral() { default boolean isCannon() { return false; } + + TeamType getTeamTypeForDTO(); + + PieceType getPieceTypeForDTO(); } diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 61262ff880..8e0c4410ae 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -34,16 +34,6 @@ public Soldier(final TeamType teamType) { this.teamType = teamType; } - @Override - public PieceType getPieceType() { - return PIECE_TYPE; - } - - @Override - public TeamType getTeamType() { - return teamType; - } - @Override public boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; @@ -56,4 +46,14 @@ public List calculateMovablePositions(Position from, BoardMediator boa } return BLUE_PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); } + + @Override + public TeamType getTeamTypeForDTO() { + return teamType; + } + + @Override + public PieceType getPieceTypeForDTO() { + return PIECE_TYPE; + } } diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java index 868ef23e85..817545f817 100644 --- a/src/main/java/janggi/dto/BoardDto.java +++ b/src/main/java/janggi/dto/BoardDto.java @@ -127,7 +127,7 @@ private static String getSpaceWithBackGround(final Position position, final Map< } private static String getChineseOf(final Piece piece) { - final Map secondaryMap = CHINESE_MAP.get(piece.getTeamType()); - return secondaryMap.get(piece.getPieceType()); + final Map secondaryMap = CHINESE_MAP.get(piece.getTeamTypeForDTO()); + return secondaryMap.get(piece.getPieceTypeForDTO()); } } From 656cd3d26ab63bcce53b96e67c750ca5905e5e03 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 12:19:06 +0900 Subject: [PATCH 120/128] =?UTF-8?q?refactor:=20board=20test=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/board/BoardTest.java | 40 +++++-------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/test/java/janggi/domain/board/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java index 32bbeacffc..c0f60287e9 100644 --- a/src/test/java/janggi/domain/board/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -50,6 +50,17 @@ void generalIsOne() { assertThat(actual).isEqualTo(expected); } + @Test + @DisplayName("빈 칸의 기물을 이동하려고 한 경우") + void failure() { + Map positionPieceMap = new LinkedHashMap<>(); + Board board = new Board(positionPieceMap); + Position position = Position.valueOf(9, 5); + + assertThatIllegalArgumentException() + .isThrownBy(() -> board.calculateMovablePositions(position)); + } + @Nested @DisplayName("빈칸 여부 테스트") class isBlank { @@ -79,33 +90,4 @@ void success_2() { assertThat(actual).isEqualTo(expected); } } - - @Nested - @DisplayName("기물 획득 테스트") - class FindPieceByPosition { - - @Test - @DisplayName("정상 테스트") - void success() { - Position position = Position.valueOf(1, 1); - Piece expected = new Cannon(TeamType.RED); - Map positionPieceMap = Map.of(position, expected); - Board board = new Board(positionPieceMap); - - Piece actual = board.getPieceInPosition(position); - - assertThat(actual).usingRecursiveComparison() - .isEqualTo(expected); - } - - @Test - @DisplayName("빈칸인 경우 예외가 발생한다.") - void failure() { - Position position = Position.valueOf(1, 1); - Board board = new Board(new LinkedHashMap<>()); - - assertThatIllegalArgumentException() - .isThrownBy(() -> board.getPieceInPosition(position)); - } - } } From c996d7c54dd07c7a2bda79ab415c73c57f616245 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 12:21:44 +0900 Subject: [PATCH 121/128] =?UTF-8?q?refactor:=20board=EC=97=90=EC=84=9C=20p?= =?UTF-8?q?iece=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=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 - TDA 적용 --- src/main/java/janggi/controller/JanggiController.java | 10 +++------- src/main/java/janggi/domain/board/Board.java | 10 +++++----- src/main/java/janggi/domain/board/BoardMediator.java | 3 --- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index 18c010b1b2..bcd6e823b6 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -6,7 +6,6 @@ import janggi.domain.board.BoardGenerator; import janggi.domain.board.setup.ElephantFormation; import janggi.domain.board.setup.SetupStrategy; -import janggi.domain.piece.Piece; import janggi.domain.team.BlueTeam; import janggi.domain.team.RedTeam; import janggi.domain.team.Team; @@ -58,8 +57,7 @@ private SetupStrategy readSetupCommand() { private void playTurn(Board board, TurnManager turnManager) { OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamTypeToString()); Position from = findFromPosition(board, turnManager); - Piece piece = board.getPieceInPosition(from); - List movable = piece.calculateMovablePositions(from, board); + List movable = board.calculateMovablePositions(from); OutputView.printBoardWithMovable(BoardDto.from(board, movable)); Position to = RetryExecutor.retry(() -> inputToPosition(movable)); board.movePiece(from, to); @@ -69,8 +67,7 @@ private void playTurn(Board board, TurnManager turnManager) { private Position findFromPosition(Board board, TurnManager turnManager) { while (true) { Position from = RetryExecutor.retry(() -> inputFromPosition(board, turnManager)); - Piece piece = board.getPieceInPosition(from); - List movable = piece.calculateMovablePositions(from, board); + List movable = board.calculateMovablePositions(from); if (!movable.isEmpty()) { return from; } @@ -83,8 +80,7 @@ private Position inputFromPosition(Board board, TurnManager turnManager) { try { OutputView.printInputFromPosition(); Position from = InputView.readPosition(); - Piece piece = board.getPieceInPosition(from); - if (!turnManager.isCurrentTurnOf(piece.getTeamType())) { + if (!board.isSameTeamType(from, turnManager.currentTeamType())) { throw new IllegalArgumentException("자신의 기물을 선택하세요."); } return from; diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index def33a0eec..c41e76414b 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -4,6 +4,7 @@ import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; public class Board implements BoardMediator { @@ -18,14 +19,13 @@ public void movePiece(final Position from, final Position to) { positionPieceMap.put(to, positionPieceMap.remove(from)); } - @Override - public boolean hasPieceAt(final Position position) { - return hasPieceIn(position); + public List calculateMovablePositions(Position from) { + return findPieceByPosition(from).calculateMovablePositions(from, this); } @Override - public Piece getPieceInPosition(final Position position) { - return findPieceByPosition(position); + public boolean hasPieceAt(final Position position) { + return hasPieceIn(position); } @Override diff --git a/src/main/java/janggi/domain/board/BoardMediator.java b/src/main/java/janggi/domain/board/BoardMediator.java index 90cf046c40..759adc1168 100644 --- a/src/main/java/janggi/domain/board/BoardMediator.java +++ b/src/main/java/janggi/domain/board/BoardMediator.java @@ -1,7 +1,6 @@ package janggi.domain.board; import janggi.domain.Position; -import janggi.domain.piece.Piece; import janggi.domain.team.TeamType; public interface BoardMediator { @@ -9,8 +8,6 @@ public interface BoardMediator { boolean hasGeneral(TeamType teamType); - Piece getPieceInPosition(Position position); - boolean isCannon(Position position); boolean isSameTeamType(Position position, TeamType teamType); From 49413caad8239689980a338d537e5e8451b776a7 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 12:49:06 +0900 Subject: [PATCH 122/128] =?UTF-8?q?refactor:=20GameManager=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - board에서 현재 팀의 왕이 있는 지 검사 --- src/main/java/janggi/controller/JanggiController.java | 6 +----- src/main/java/janggi/domain/GameManager.java | 11 ----------- src/main/java/janggi/domain/board/Board.java | 6 +++--- src/test/java/janggi/domain/board/BoardTest.java | 7 ++----- 4 files changed, 6 insertions(+), 24 deletions(-) delete mode 100644 src/main/java/janggi/domain/GameManager.java diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index bcd6e823b6..cd222f0536 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -1,6 +1,5 @@ package janggi.controller; -import janggi.domain.GameManager; import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.board.BoardGenerator; @@ -19,16 +18,13 @@ public class JanggiController { - private final GameManager gameManager; - public JanggiController() { - gameManager = new GameManager(); } public void run() { Board board = BoardGenerator.generate(setupRedTeam(), setupBlueTeam()); TurnManager turnManager = new TurnManager(); - while (gameManager.isGeneralAlive(turnManager.currentTeamType(), board)) { + while (board.hasGeneral(turnManager.currentTeamType())) { playTurn(board, turnManager); } turnManager.changeTurn(); diff --git a/src/main/java/janggi/domain/GameManager.java b/src/main/java/janggi/domain/GameManager.java deleted file mode 100644 index 2bd6159290..0000000000 --- a/src/main/java/janggi/domain/GameManager.java +++ /dev/null @@ -1,11 +0,0 @@ -package janggi.domain; - -import janggi.domain.board.BoardMediator; -import janggi.domain.team.TeamType; - -public class GameManager { - - public boolean isGeneralAlive(TeamType teamType, BoardMediator boardMediator) { - return boardMediator.hasGeneral(teamType); - } -} diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index c41e76414b..3f32e52acc 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -53,9 +53,9 @@ private boolean hasPieceIn(final Position position) { } private Piece findPieceByPosition(final Position position) { - if (!hasPieceIn(position)) { - throw new IllegalArgumentException("요청된 위치에는 기물이 존재하지 않습니다."); + if (hasPieceIn(position)) { + return positionPieceMap.get(position); } - return positionPieceMap.get(position); + throw new IllegalArgumentException("요청된 위치에는 기물이 존재하지 않습니다."); } } diff --git a/src/test/java/janggi/domain/board/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java index c0f60287e9..8a13e76ff6 100644 --- a/src/test/java/janggi/domain/board/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.GameManager; import janggi.domain.Position; import janggi.domain.piece.Cannon; import janggi.domain.piece.General; @@ -28,8 +27,7 @@ void generalIsTwo() { Board board = new Board(positionPieceMap); boolean expected = true; - GameManager gameManager = new GameManager(); - boolean actual = gameManager.isGeneralAlive(turnManager.currentTeamType(), board); + boolean actual = board.hasGeneral(turnManager.currentTeamType()); assertThat(actual).isEqualTo(expected); } @@ -44,8 +42,7 @@ void generalIsOne() { Board board = new Board(positionPieceMap); boolean expected = false; - GameManager gameManager = new GameManager(); - boolean actual = gameManager.isGeneralAlive(turnManager.currentTeamType(), board); + boolean actual = board.hasGeneral(turnManager.currentTeamType()); assertThat(actual).isEqualTo(expected); } From af33f4eb4e6a6f62bd93b1b4568e247fd4bfb6f2 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 13:40:28 +0900 Subject: [PATCH 123/128] =?UTF-8?q?refactor:=20BoardDTO=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20OutputView=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/controller/JanggiController.java | 2 +- src/main/java/janggi/dto/BoardDto.java | 127 +----------------- src/main/java/janggi/dto/PieceDto.java | 7 + src/main/java/janggi/view/OutputView.java | 86 +++++++++++- 4 files changed, 95 insertions(+), 127 deletions(-) create mode 100644 src/main/java/janggi/dto/PieceDto.java diff --git a/src/main/java/janggi/controller/JanggiController.java b/src/main/java/janggi/controller/JanggiController.java index cd222f0536..41f9e47ba2 100644 --- a/src/main/java/janggi/controller/JanggiController.java +++ b/src/main/java/janggi/controller/JanggiController.java @@ -54,7 +54,7 @@ private void playTurn(Board board, TurnManager turnManager) { OutputView.printBoard(BoardDto.from(board), turnManager.currentTeamTypeToString()); Position from = findFromPosition(board, turnManager); List movable = board.calculateMovablePositions(from); - OutputView.printBoardWithMovable(BoardDto.from(board, movable)); + OutputView.printBoardWithMovable(BoardDto.from(board), movable); Position to = RetryExecutor.retry(() -> inputToPosition(movable)); board.movePiece(from, to); turnManager.changeTurn(); diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java index 817545f817..937866c13f 100644 --- a/src/main/java/janggi/dto/BoardDto.java +++ b/src/main/java/janggi/dto/BoardDto.java @@ -1,133 +1,18 @@ package janggi.dto; -import static janggi.domain.Position.MAXIMUM_COLUMN; -import static janggi.domain.Position.MAXIMUM_ROW; -import static janggi.domain.Position.MINIMUM_COLUMN; -import static janggi.domain.Position.MINIMUM_ROW; - import janggi.domain.Position; import janggi.domain.board.Board; import janggi.domain.piece.Piece; -import janggi.domain.piece.PieceType; -import janggi.domain.team.TeamType; -import janggi.view.ConsoleColor; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashMap; import java.util.Map; -public record BoardDto( - List rowStatuses -) { - - private static final Map> CHINESE_MAP; - private static final String EMPTY_SPACE = "*"; - private static final String DELIMITER = " "; - private static final String[] INDEX_LABELS = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; - - static { - CHINESE_MAP = Map.of( - TeamType.RED, Map.of( - PieceType.GENERAL, ConsoleColor.red("漢"), - PieceType.GUARD, ConsoleColor.red("士"), - PieceType.CHARIOT, ConsoleColor.red("車"), - PieceType.CANNON, ConsoleColor.red("包"), - PieceType.HORSE, ConsoleColor.red("馬"), - PieceType.ELEPHANT, ConsoleColor.red("象"), - PieceType.SOLDIER, ConsoleColor.red("兵") - ), - TeamType.BLUE, Map.of( - PieceType.GENERAL, ConsoleColor.blue("楚"), - PieceType.GUARD, ConsoleColor.blue("士"), - PieceType.CHARIOT, ConsoleColor.blue("車"), - PieceType.CANNON, ConsoleColor.blue("包"), - PieceType.HORSE, ConsoleColor.blue("馬"), - PieceType.ELEPHANT, ConsoleColor.blue("象"), - PieceType.SOLDIER, ConsoleColor.blue("卒") - )); - } +public record BoardDto(Map pieceMap) { public static BoardDto from(final Board board) { - final List rowStatuses = new ArrayList<>(); final Map positionPieceMap = board.getPositionPieceMapForDTO(); - rowStatuses.add(generateColumnIndex()); - for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { - rowStatuses.add(composeRowStatus(row, positionPieceMap)); - } - return new BoardDto(rowStatuses); - } - - public static BoardDto from(final Board board, List movable) { - final List rowStatuses = new ArrayList<>(); - final Map positionPieceMap = board.getPositionPieceMapForDTO(); - rowStatuses.add(generateColumnIndex()); - for (int row = MINIMUM_ROW; row <= MAXIMUM_ROW; row++) { - rowStatuses.add(composeRowStatusWithMovable(row, positionPieceMap, movable)); - } - return new BoardDto(rowStatuses); - } - - private static String generateColumnIndex() { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(DELIMITER); - stringBuilder.append(DELIMITER); - for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { - stringBuilder.append(DELIMITER); - stringBuilder.append(INDEX_LABELS[column - 1]); - } - return stringBuilder.toString(); - } - - private static String composeRowStatus(final int row, final Map positionPieceMap) { - final StringBuilder stringBuilder = new StringBuilder(); - Position current; - stringBuilder.append(DELIMITER); - stringBuilder.append(INDEX_LABELS[row - 1]); - for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { - current = Position.valueOf(row, column); - stringBuilder.append(DELIMITER); - stringBuilder.append(getSpace(current, positionPieceMap)); - } - - return stringBuilder.toString(); - } - - private static String composeRowStatusWithMovable(final int row, final Map positionPieceMap, - List movable) { - final StringBuilder stringBuilder = new StringBuilder(); - Position current; - stringBuilder.append(DELIMITER); - stringBuilder.append(INDEX_LABELS[row - 1]); - for (int column = MINIMUM_COLUMN; column <= MAXIMUM_COLUMN; column++) { - current = Position.valueOf(row, column); - stringBuilder.append(DELIMITER); - if (movable.contains(current)) { - stringBuilder.append(getSpaceWithBackGround(current, positionPieceMap)); - continue; - } - stringBuilder.append(getSpace(current, positionPieceMap)); - } - - return stringBuilder.toString(); - } - - private static String getSpace(final Position position, final Map positionPieceMap) { - if (positionPieceMap.containsKey(position)) { - final Piece piece = positionPieceMap.get(position); - return getChineseOf(piece); - } - return EMPTY_SPACE; - } - - private static String getSpaceWithBackGround(final Position position, final Map positionPieceMap) { - if (positionPieceMap.containsKey(position)) { - final Piece piece = positionPieceMap.get(position); - return ConsoleColor.getGreenBackground(getChineseOf(piece)); - } - return ConsoleColor.getGreenBackground(EMPTY_SPACE); - } - - private static String getChineseOf(final Piece piece) { - final Map secondaryMap = CHINESE_MAP.get(piece.getTeamTypeForDTO()); - return secondaryMap.get(piece.getPieceTypeForDTO()); + final Map pieceDtoMap = new LinkedHashMap<>(); + positionPieceMap.forEach((position, piece) -> + pieceDtoMap.put(position, new PieceDto(piece.getPieceTypeForDTO(), piece.getTeamTypeForDTO()))); + return new BoardDto(Map.copyOf(pieceDtoMap)); } } diff --git a/src/main/java/janggi/dto/PieceDto.java b/src/main/java/janggi/dto/PieceDto.java new file mode 100644 index 0000000000..f8a7d2ac65 --- /dev/null +++ b/src/main/java/janggi/dto/PieceDto.java @@ -0,0 +1,7 @@ +package janggi.dto; + +import janggi.domain.piece.PieceType; +import janggi.domain.team.TeamType; + +public record PieceDto(PieceType pieceType, TeamType teamType) { +} \ No newline at end of file diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index c3960fb860..3a033b3478 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -1,11 +1,20 @@ package janggi.view; +import janggi.domain.Position; +import janggi.domain.piece.PieceType; import janggi.domain.team.TeamType; import janggi.dto.BoardDto; +import janggi.dto.PieceDto; import java.util.List; +import java.util.Map; public final class OutputView { + private static final String ERROR_PREFIX = "[ERROR]: "; + private static final String EMPTY_SPACE = "*"; + private static final String DELIMITER = " "; + private static final String[] INDEX_LABELS = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; + private static final Map> CHINESE_MAP; private static final List ELEPHANT_FORMATION_DESCRIPTIONS = List.of( "1. 안상 차림", "2. 바깥상 차림", @@ -13,6 +22,28 @@ public final class OutputView { "4. 오른상 차림" ); + static { + CHINESE_MAP = Map.of( + TeamType.RED, Map.of( + PieceType.GENERAL, "漢", + PieceType.GUARD, "士", + PieceType.CHARIOT, "車", + PieceType.CANNON, "包", + PieceType.HORSE, "馬", + PieceType.ELEPHANT, "象", + PieceType.SOLDIER, "兵" + ), + TeamType.BLUE, Map.of( + PieceType.GENERAL, "楚", + PieceType.GUARD, "士", + PieceType.CHARIOT, "車", + PieceType.CANNON, "包", + PieceType.HORSE, "馬", + PieceType.ELEPHANT, "象", + PieceType.SOLDIER, "卒" + )); + } + private OutputView() { } @@ -29,13 +60,13 @@ public static void printErrorMessage(String message) { public static void printBoard(final BoardDto boardDto, String currentTeamType) { System.out.println(currentTeamType + "의 차례입니다."); - printBoardWithMovable(boardDto); + printBoardWithMovable(boardDto, List.of()); } - public static void printBoardWithMovable(BoardDto boardDto) { - final List rowStatuses = boardDto.rowStatuses(); - for (String rowStatus : rowStatuses) { - System.out.println(rowStatus); + public static void printBoardWithMovable(final BoardDto boardDto, final List movablePositions) { + System.out.println(generateColumnIndex()); + for (int row = Position.MINIMUM_ROW; row <= Position.MAXIMUM_ROW; row++) { + System.out.println(composeRowStatus(row, boardDto.pieceMap(), movablePositions)); } } @@ -50,4 +81,49 @@ public static void printInputToPosition() { public static void printGameOverMessage(String teamType) { System.out.println(teamType + "의 승리로 게임이 종료되었습니다."); } + + private static String generateColumnIndex() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(DELIMITER).append(DELIMITER); + for (int column = Position.MINIMUM_COLUMN; column <= Position.MAXIMUM_COLUMN; column++) { + stringBuilder.append(DELIMITER).append(INDEX_LABELS[column - 1]); + } + return stringBuilder.toString(); + } + + private static String composeRowStatus(final int row, final Map pieceMap, + final List movablePositions) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(DELIMITER).append(INDEX_LABELS[row - 1]); + for (int column = Position.MINIMUM_COLUMN; column <= Position.MAXIMUM_COLUMN; column++) { + Position position = Position.valueOf(row, column); + stringBuilder.append(DELIMITER).append(getPositionDisplay(position, pieceMap, movablePositions)); + } + return stringBuilder.toString(); + } + + private static String getPositionDisplay(final Position position, final Map pieceMap, + final List movablePositions) { + String cellText = toCellText(position, pieceMap); + if (movablePositions.contains(position)) { + return ConsoleColor.getGreenBackground(cellText); + } + return cellText; + } + + private static String toCellText(final Position position, final Map pieceMap) { + PieceDto pieceDto = pieceMap.get(position); + if (pieceDto == null) { + return EMPTY_SPACE; + } + return applyTeamColor(pieceDto); + } + + private static String applyTeamColor(final PieceDto pieceDto) { + String chinese = CHINESE_MAP.get(pieceDto.teamType()).get(pieceDto.pieceType()); + if (pieceDto.teamType() == TeamType.RED) { + return ConsoleColor.red(chinese); + } + return ConsoleColor.blue(chinese); + } } From 679325376e85ce2ebb3168e2c50539d4441f0bb6 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 13:50:53 +0900 Subject: [PATCH 124/128] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=A7=81=EB=84=98?= =?UTF-8?q?=EB=B2=84=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/janggi/domain/Position.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 8135edbc26..60e35e6a29 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -41,13 +41,13 @@ public static Position valueOf(final int row, final int column) { private static void validateRowRange(final int row) { if (row < MINIMUM_ROW || row > MAXIMUM_ROW) { - throw new IllegalArgumentException("행 입력은 1~10을 입력해야 합니다."); + throw new IllegalArgumentException(String.format("행 입력은 %d~%d을 입력해야 합니다.", MINIMUM_ROW, MAXIMUM_ROW)); } } private static void validateColumnRange(final int column) { if (column < MINIMUM_COLUMN || column > MAXIMUM_COLUMN) { - throw new IllegalArgumentException("열 입력은 1~9을 입력해야 합니다."); + throw new IllegalArgumentException(String.format("열 입력은 %d~%d을 입력해야 합니다.", MINIMUM_COLUMN, MAXIMUM_COLUMN)); } } From 57771fb07fb35af87b0cb39aa41a8aa03dad1431 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 15:29:49 +0900 Subject: [PATCH 125/128] =?UTF-8?q?refactor:=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EB=A1=9C=EC=A7=81=EC=9D=84=20AbstractPiec?= =?UTF-8?q?e=20=EC=B6=94=EC=83=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C?= =?UTF-8?q?=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/piece/AbstractPiece.java | 38 +++++++++++++++++++ src/main/java/janggi/domain/piece/Cannon.java | 29 ++++---------- .../java/janggi/domain/piece/Chariot.java | 29 ++++---------- .../java/janggi/domain/piece/Elephant.java | 32 ++++------------ .../java/janggi/domain/piece/General.java | 31 ++++----------- src/main/java/janggi/domain/piece/Guard.java | 31 ++++----------- src/main/java/janggi/domain/piece/Horse.java | 31 ++++----------- .../java/janggi/domain/piece/Soldier.java | 35 +++++------------ 8 files changed, 94 insertions(+), 162 deletions(-) create mode 100644 src/main/java/janggi/domain/piece/AbstractPiece.java diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java new file mode 100644 index 0000000000..35ac492175 --- /dev/null +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -0,0 +1,38 @@ +package janggi.domain.piece; + +import janggi.domain.Position; +import janggi.domain.board.BoardMediator; +import janggi.domain.team.TeamType; +import java.util.List; + +public abstract class AbstractPiece implements Piece { + protected final TeamType teamType; + + protected AbstractPiece(TeamType teamType) { + this.teamType = teamType; + } + + protected abstract PieceType getPieceType(); + + protected abstract PieceAction getPieceAction(); + + @Override + public boolean isSameTeamType(final TeamType teamType) { + return this.teamType == teamType; + } + + @Override + public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + return getPieceAction().calculateMovablePositions(from, this.teamType, boardMediator); + } + + @Override + public TeamType getTeamTypeForDTO() { + return this.teamType; + } + + @Override + public PieceType getPieceTypeForDTO() { + return getPieceType(); + } +} diff --git a/src/main/java/janggi/domain/piece/Cannon.java b/src/main/java/janggi/domain/piece/Cannon.java index 08c6b7eaca..31745c5c2c 100644 --- a/src/main/java/janggi/domain/piece/Cannon.java +++ b/src/main/java/janggi/domain/piece/Cannon.java @@ -1,15 +1,12 @@ package janggi.domain.piece; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.CannonMoveRule; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.team.TeamType; import java.util.List; -public class Cannon implements Piece { - +public class Cannon extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.CANNON; private static final PieceAction PIECE_ACTION; @@ -22,20 +19,8 @@ public class Cannon implements Piece { PIECE_ACTION = new PieceAction(movementStrategies); } - private final TeamType teamType; - - public Cannon(final TeamType teamType) { - this.teamType = teamType; - } - - @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; - } - - @Override - public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public Cannon(TeamType teamType) { + super(teamType); } @Override @@ -44,12 +29,12 @@ public boolean isCannon() { } @Override - public TeamType getTeamTypeForDTO() { - return teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + protected PieceAction getPieceAction() { + return PIECE_ACTION; } } diff --git a/src/main/java/janggi/domain/piece/Chariot.java b/src/main/java/janggi/domain/piece/Chariot.java index d4ede53b12..62d59cd292 100644 --- a/src/main/java/janggi/domain/piece/Chariot.java +++ b/src/main/java/janggi/domain/piece/Chariot.java @@ -3,8 +3,6 @@ import static janggi.domain.Position.MAXIMUM_COLUMN; import static janggi.domain.Position.MAXIMUM_ROW; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; @@ -12,8 +10,7 @@ import janggi.domain.team.TeamType; import java.util.List; -public class Chariot implements Piece { - +public class Chariot extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.CHARIOT; private static final PieceAction PIECE_ACTION; @@ -26,29 +23,17 @@ public class Chariot implements Piece { PIECE_ACTION = new PieceAction(movementStrategies); } - private final TeamType teamType; - - public Chariot(final TeamType teamType) { - this.teamType = teamType; - } - - @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; - } - - @Override - public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public Chariot(TeamType teamType) { + super(teamType); } @Override - public TeamType getTeamTypeForDTO() { - return teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + protected PieceAction getPieceAction() { + return PIECE_ACTION; } } diff --git a/src/main/java/janggi/domain/piece/Elephant.java b/src/main/java/janggi/domain/piece/Elephant.java index e2cd3822e6..ec1c9f8c41 100644 --- a/src/main/java/janggi/domain/piece/Elephant.java +++ b/src/main/java/janggi/domain/piece/Elephant.java @@ -1,15 +1,12 @@ package janggi.domain.piece; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.movement.StepMoveRule; import janggi.domain.team.TeamType; import java.util.List; -public class Elephant implements Piece { - +public class Elephant extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.ELEPHANT; private static final PieceAction PIECE_ACTION; @@ -26,30 +23,17 @@ public class Elephant implements Piece { PIECE_ACTION = new PieceAction(movementStrategies); } - private final TeamType teamType; - - public Elephant(final TeamType teamType) { - this.teamType = teamType; - } - - @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; - } - - @Override - public List calculateMovablePositions(final Position from, - final BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public Elephant(TeamType teamType) { + super(teamType); } @Override - public TeamType getTeamTypeForDTO() { - return teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + protected PieceAction getPieceAction() { + return PIECE_ACTION; } -} +} \ No newline at end of file diff --git a/src/main/java/janggi/domain/piece/General.java b/src/main/java/janggi/domain/piece/General.java index fbabc08edc..6a29048af1 100644 --- a/src/main/java/janggi/domain/piece/General.java +++ b/src/main/java/janggi/domain/piece/General.java @@ -1,7 +1,5 @@ package janggi.domain.piece; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; @@ -9,8 +7,7 @@ import janggi.domain.team.TeamType; import java.util.List; -public class General implements Piece { - +public class General extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.GENERAL; private static final PieceAction PIECE_ACTION; @@ -27,20 +24,8 @@ public class General implements Piece { PIECE_ACTION = new PieceAction(movementStrategies); } - private final TeamType teamType; - - public General(final TeamType teamType) { - this.teamType = teamType; - } - - @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; - } - - @Override - public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public General(TeamType teamType) { + super(teamType); } @Override @@ -49,12 +34,12 @@ public boolean isGeneral() { } @Override - public TeamType getTeamTypeForDTO() { - return teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + protected PieceAction getPieceAction() { + return PIECE_ACTION; } -} +} \ No newline at end of file diff --git a/src/main/java/janggi/domain/piece/Guard.java b/src/main/java/janggi/domain/piece/Guard.java index 5f8450b5c5..eac8f1a004 100644 --- a/src/main/java/janggi/domain/piece/Guard.java +++ b/src/main/java/janggi/domain/piece/Guard.java @@ -1,7 +1,5 @@ package janggi.domain.piece; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; @@ -9,8 +7,7 @@ import janggi.domain.team.TeamType; import java.util.List; -public class Guard implements Piece { - +public class Guard extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.GUARD; private static final PieceAction PIECE_ACTION; @@ -27,29 +24,17 @@ public class Guard implements Piece { PIECE_ACTION = new PieceAction(movementStrategies); } - private final TeamType teamType; - - public Guard(final TeamType teamType) { - this.teamType = teamType; - } - - @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; - } - - @Override - public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public Guard(TeamType teamType) { + super(teamType); } @Override - public TeamType getTeamTypeForDTO() { - return teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + protected PieceAction getPieceAction() { + return PIECE_ACTION; } -} +} \ No newline at end of file diff --git a/src/main/java/janggi/domain/piece/Horse.java b/src/main/java/janggi/domain/piece/Horse.java index 9360b5cc89..79acd43886 100644 --- a/src/main/java/janggi/domain/piece/Horse.java +++ b/src/main/java/janggi/domain/piece/Horse.java @@ -1,15 +1,12 @@ package janggi.domain.piece; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.movement.StepMoveRule; import janggi.domain.team.TeamType; import java.util.List; -public class Horse implements Piece { - +public class Horse extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.HORSE; private static final PieceAction PIECE_ACTION; @@ -26,29 +23,17 @@ public class Horse implements Piece { PIECE_ACTION = new PieceAction(movementStrategies); } - private final TeamType teamType; - - public Horse(final TeamType teamType) { - this.teamType = teamType; - } - - @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; - } - - @Override - public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - return PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + public Horse(TeamType teamType) { + super(teamType); } @Override - public TeamType getTeamTypeForDTO() { - return teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + protected PieceAction getPieceAction() { + return PIECE_ACTION; } -} +} \ No newline at end of file diff --git a/src/main/java/janggi/domain/piece/Soldier.java b/src/main/java/janggi/domain/piece/Soldier.java index 8e0c4410ae..91ef785816 100644 --- a/src/main/java/janggi/domain/piece/Soldier.java +++ b/src/main/java/janggi/domain/piece/Soldier.java @@ -1,7 +1,5 @@ package janggi.domain.piece; -import janggi.domain.Position; -import janggi.domain.board.BoardMediator; import janggi.domain.movement.Direction; import janggi.domain.movement.MoveRule; import janggi.domain.movement.Movement; @@ -9,8 +7,7 @@ import janggi.domain.team.TeamType; import java.util.List; -public class Soldier implements Piece { - +public class Soldier extends AbstractPiece { private static final PieceType PIECE_TYPE = PieceType.SOLDIER; private static final PieceAction RED_PIECE_ACTION; private static final PieceAction BLUE_PIECE_ACTION; @@ -28,32 +25,20 @@ public class Soldier implements Piece { BLUE_PIECE_ACTION = new PieceAction(blueMovementStrategies); } - private final TeamType teamType; - - public Soldier(final TeamType teamType) { - this.teamType = teamType; + public Soldier(TeamType teamType) { + super(teamType); } @Override - public boolean isSameTeamType(final TeamType teamType) { - return this.teamType == teamType; + protected PieceType getPieceType() { + return PIECE_TYPE; } @Override - public List calculateMovablePositions(Position from, BoardMediator boardMediator) { - if (teamType == TeamType.RED) { - return RED_PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); + protected PieceAction getPieceAction() { + if (this.teamType == TeamType.RED) { + return RED_PIECE_ACTION; } - return BLUE_PIECE_ACTION.calculateMovablePositions(from, teamType, boardMediator); - } - - @Override - public TeamType getTeamTypeForDTO() { - return teamType; - } - - @Override - public PieceType getPieceTypeForDTO() { - return PIECE_TYPE; + return BLUE_PIECE_ACTION; } -} +} \ No newline at end of file From 8ce46f6d966da8c5c127d31d40c607f3d2141510 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 15:34:30 +0900 Subject: [PATCH 126/128] =?UTF-8?q?refactor:=20AbstractPiece=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90=20final=20?= =?UTF-8?q?=ED=82=A4=EC=9B=8C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자식클래스에서 오버라이딩 방지 --- src/main/java/janggi/domain/piece/AbstractPiece.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java index 35ac492175..99f44dc53c 100644 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -17,22 +17,22 @@ protected AbstractPiece(TeamType teamType) { protected abstract PieceAction getPieceAction(); @Override - public boolean isSameTeamType(final TeamType teamType) { + public final boolean isSameTeamType(final TeamType teamType) { return this.teamType == teamType; } @Override - public List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { + public final List calculateMovablePositions(final Position from, final BoardMediator boardMediator) { return getPieceAction().calculateMovablePositions(from, this.teamType, boardMediator); } @Override - public TeamType getTeamTypeForDTO() { + public final TeamType getTeamTypeForDTO() { return this.teamType; } @Override - public PieceType getPieceTypeForDTO() { + public final PieceType getPieceTypeForDTO() { return getPieceType(); } } From 601c5009a4dded93491b788af0dcb49131fe83a1 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 16:43:51 +0900 Subject: [PATCH 127/128] =?UTF-8?q?refactor:=20=ED=8F=AC=20=ED=8F=AC?= =?UTF-8?q?=ED=9A=8D=EB=B6=88=EA=B0=80=20=EB=A1=9C=EC=A7=81=EC=9D=84=20Can?= =?UTF-8?q?nonMoveRule=EC=97=90=EC=84=9C=20=EC=B2=98=EB=A6=AC=ED=95=98?= =?UTF-8?q?=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 --- .../domain/movement/CannonMoveRule.java | 18 +++++++++++--- .../java/janggi/domain/movement/Movement.java | 24 ------------------- .../java/janggi/domain/piece/CannonTest.java | 3 +-- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/main/java/janggi/domain/movement/CannonMoveRule.java b/src/main/java/janggi/domain/movement/CannonMoveRule.java index c72bae9838..3392ebecfc 100644 --- a/src/main/java/janggi/domain/movement/CannonMoveRule.java +++ b/src/main/java/janggi/domain/movement/CannonMoveRule.java @@ -5,7 +5,6 @@ import janggi.domain.Position; import janggi.domain.board.BoardMediator; import janggi.domain.team.TeamType; -import java.util.ArrayList; import java.util.List; public class CannonMoveRule implements MoveRule { @@ -17,16 +16,29 @@ public CannonMoveRule(final Direction direction) { } @Override - public List execute(Position from, final TeamType teamType, BoardMediator boardMediator) { + public List execute(Position from, final TeamType teamType, final BoardMediator boardMediator) { from = movement.findFirstOccupiedPositionOrMax(from, boardMediator); // 포다리 찾기 if (isInvalidBridge(from, boardMediator)) { return List.of(); } - return new ArrayList<>(movement.calculateTracesForCannon(from, teamType, boardMediator)); + return removeCannonFromPositions( + movement.calculateTraces(from, teamType, boardMediator), boardMediator); } // 포다리가 안되는 경우 검증(빈 공간인지 or 포다리가 포 인지) private boolean isInvalidBridge(final Position bridge, final BoardMediator boardMediator) { return !boardMediator.hasPieceAt(bridge) || boardMediator.isCannon(bridge); } + + private List removeCannonFromPositions(final List movablePositions, + final BoardMediator boardMediator) { + return movablePositions.stream() + .filter(position -> !isCannonPosition(position, boardMediator)) + .toList(); + } + + private boolean isCannonPosition(final Position position, final BoardMediator boardMediator) { + return boardMediator.hasPieceAt(position) && boardMediator.isCannon(position); + } + } diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index bf5820efeb..751bed8d64 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -98,30 +98,6 @@ public List calculateTraces(final Position from, final TeamType teamTy return traces; } - // 이동 가능한 경로의 자취 위치 리스트를 반환한다. - // 경로에 장애물을 만나면 그때까지의 리스트를 반환하고, 적을 만난다면 적의 좌표를 포함하여 반환한다. - public List calculateTracesForCannon(final Position from, final TeamType teamType, - final BoardMediator boardMediator) { - final List traces = new ArrayList<>(); - Position prev = from; - for (int distance = 1; distance <= maxDistance; distance++) { - Position to = calculateNextPosition(from, distance); - if (prev.equals(to)) { - return traces; - } - if (!hasPieceAt(to, boardMediator)) { - traces.add(to); - prev = to; - continue; - } - if (!boardMediator.isSameTeamType(to, teamType) && !boardMediator.isCannon(to)) { - traces.add(to); - } - return traces; - } - return traces; - } - private Position calculateNextPosition(final Position from, final int distance) { return from.calculateNext(distance, direction); } diff --git a/src/test/java/janggi/domain/piece/CannonTest.java b/src/test/java/janggi/domain/piece/CannonTest.java index 519ab01780..7ecd764f12 100644 --- a/src/test/java/janggi/domain/piece/CannonTest.java +++ b/src/test/java/janggi/domain/piece/CannonTest.java @@ -51,8 +51,7 @@ void success_1() { Position.valueOf(9, 7), Position.valueOf(10, 7)); - List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), - board); + List actual = cannon.calculateMovablePositions(Position.valueOf(6, 7), board); assertThat(actual).hasSameElementsAs(expected); } From 5622ab9670ccef5fa8400adf58efa5a067d26c61 Mon Sep 17 00:00:00 2001 From: mvg01 Date: Sat, 4 Apr 2026 17:59:37 +0900 Subject: [PATCH 128/128] =?UTF-8?q?refactor:=20movement=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EB=82=B4=EB=B6=80=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=9D=98=20depth=20=EC=B5=9C=EC=86=8C=ED=99=94,=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/movement/Movement.java | 71 ++++++++----------- .../janggi/domain/movement/MovementTest.java | 16 ++--- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/main/java/janggi/domain/movement/Movement.java b/src/main/java/janggi/domain/movement/Movement.java index 751bed8d64..3bca4ff2f6 100644 --- a/src/main/java/janggi/domain/movement/Movement.java +++ b/src/main/java/janggi/domain/movement/Movement.java @@ -8,6 +8,7 @@ public class Movement { + private static final int ONE_STEP = 1; private final int maxDistance; private final Direction direction; @@ -20,46 +21,29 @@ public boolean canMove(final Position from) { return from.checkNextBound(maxDistance, direction); } - // 마지막 movement에서만 사용 - // 현재 기물이 다음으로 가는 곳에서 갈 수 있는 칸이 있는지 + // 마지막 movement에서만 사용, 1칸 이동으로 고정 public boolean hasReachablePosition(Position from, final TeamType teamType, final BoardMediator boardMediator) { - for (int distance = 1; distance <= maxDistance; distance++) { - Position to = calculateNextPosition(from, distance); - if (!hasPieceAt(to, boardMediator)) { - return true; - } - if (!boardMediator.isSameTeamType(to, teamType)) { - return true; - } - } - return false; + Position to = calculateNextPosition(from, ONE_STEP); + return !hasPieceAt(to, boardMediator) || !boardMediator.isSameTeamType(to, teamType); } - // 이동 경로 중 막히는지 + // 이동 경로 중 막히는지, 1칸 이동으로 고정 public boolean isBlocked(final Position from, final BoardMediator boardMediator) { - for (int distance = 1; distance <= maxDistance; distance++) { - final Position to = calculateNextPosition(from, distance); - if (hasPieceAt(to, boardMediator)) { - return true; - } - } - return false; + final Position to = calculateNextPosition(from, ONE_STEP); + return hasPieceAt(to, boardMediator); } - // 처음 만나는 기물 찾기(그 기물이 적군이라면 기물의 위치 반환, 아군이라면 이전 위치 반환) + // 1칸 움직였을 때, 갈 수 있는 위치 반환 public Position calculateDestination(final Position from, final TeamType teamType, final BoardMediator boardMediator) { - for (int distance = 1; distance <= maxDistance; distance++) { - final Position to = calculateNextPosition(from, distance); - if (!hasPieceAt(to, boardMediator)) { - continue; - } - if (boardMediator.isSameTeamType(to, teamType)) { - return calculateNextPosition(from, distance - 1); - } + final Position to = calculateNextPosition(from, ONE_STEP); + if (!hasPieceAt(to, boardMediator)) { return to; } - return calculateNextPosition(from, maxDistance); + if (boardMediator.isSameTeamType(to, teamType)) { + return from; + } + return to; } // 처음 만나는 기물 위치 반환, 만약 끝까지 가도 없으면 그 끝 위치 반환 @@ -79,25 +63,30 @@ public Position findFirstOccupiedPositionOrMax(final Position from, public List calculateTraces(final Position from, final TeamType teamType, final BoardMediator boardMediator) { final List traces = new ArrayList<>(); - Position prev = from; for (int distance = 1; distance <= maxDistance; distance++) { + if (!from.checkNextBound(distance, direction)) { + break; + } Position to = calculateNextPosition(from, distance); - if (prev.equals(to)) { + if (processPosition(to, traces, teamType, boardMediator)) { return traces; } - if (!hasPieceAt(to, boardMediator)) { - traces.add(to); - prev = to; - continue; - } - if (!boardMediator.isSameTeamType(to, teamType)) { - traces.add(to); - } - return traces; } return traces; } + private boolean processPosition(final Position to, final List traces, TeamType teamType, + BoardMediator boardMediator) { + if (!hasPieceAt(to, boardMediator)) { + traces.add(to); + return false; + } + if (!boardMediator.isSameTeamType(to, teamType)) { + traces.add(to); + } + return true; + } + private Position calculateNextPosition(final Position from, final int distance) { return from.calculateNext(distance, direction); } diff --git a/src/test/java/janggi/domain/movement/MovementTest.java b/src/test/java/janggi/domain/movement/MovementTest.java index eb4bf4a111..083532c651 100644 --- a/src/test/java/janggi/domain/movement/MovementTest.java +++ b/src/test/java/janggi/domain/movement/MovementTest.java @@ -150,13 +150,13 @@ void setUp() { @DisplayName("경로에 아군이 있는 경우") void success_1() { // given - positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.RED)); + positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.RED)); Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); - int maxDistance = 4; + int maxDistance = 1; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); - Position expected = Position.valueOf(5, 5); + Position expected = Position.valueOf(5, 3); // when Position actual = Movement.calculateDestination(from, TeamType.RED, board); @@ -169,13 +169,13 @@ void success_1() { @DisplayName("경로에 적군이 있는 경우") void success_2() { // given - positionPieceMap.put(Position.valueOf(5, 6), new Soldier(TeamType.BLUE)); + positionPieceMap.put(Position.valueOf(5, 4), new Soldier(TeamType.BLUE)); Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); - int maxDistance = 4; + int maxDistance = 1; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); - Position expected = Position.valueOf(5, 6); + Position expected = Position.valueOf(5, 4); // when Position actual = Movement.calculateDestination(from, TeamType.RED, board); @@ -190,10 +190,10 @@ void success_3() { // given Board board = new Board(positionPieceMap); Position from = Position.valueOf(5, 3); - int maxDistance = 4; + int maxDistance = 1; Direction direction = Direction.RIGHT; Movement Movement = new Movement(maxDistance, direction); - Position expected = Position.valueOf(5, 7); + Position expected = Position.valueOf(5, 4); // when Position actual = Movement.calculateDestination(from, TeamType.RED, board);