From dbc400820adaf2a363c5e5de462823c21cae0973 Mon Sep 17 00:00:00 2001 From: smiinii Date: Wed, 25 Mar 2026 15:24:53 +0900 Subject: [PATCH 01/70] =?UTF-8?q?docs:=20README=EC=97=90=20=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=20=EA=B7=9C=EC=B9=99=20=EB=B0=8F=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?/=EC=B6=9C=EB=A0=A5=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9775dda0ae..e9ca96dfd2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,95 @@ # java-janggi -장기 미션 저장소 +## 기능 + +### 게임 초기화 + +- 한나라가 위, 초나라를 아래로 위치시켜 보드를 초기화한다. + +### 게임 진행 + +- 초나라 선, 한나라 후로 게임이 반복적으로 진행된다. +- 입력을 받은 좌표와 기물 규칙에 따라 기물을 이동시킨다. +- 궁을 잡는 수를 두면 장군이다. +- 장군을 피하는 수를 두면 멍군이다. +- 빅장일 때 게임을 종료하기 싫으면 빅장을 깨뜨리는 수를 둘 수 있다. + +### 기물 이동 규칙 + +| **기물** | **기본 이동 방식** | **궁성(3x3) 내 특수 규칙** | **특징 (구현 시 고려사항)** | +| --- | --- | --- | --- | +| **궁(將/楚)** | 상하좌우 1칸 | 대각선 선을 따라 1칸 이동 가능 | 궁성 밖으로 절대 나갈 수 없음. | +| **사(士)** | 상하좌우 1칸 | 대각선 선을 따라 1칸 이동 가능 | 궁성 밖으로 절대 나갈 수 없음. | +| **차(車)** | 상하좌우 직선으로 거리 제한 없이 이동 | 대각선 선을 따라 이동 가능 | 경로에 다른 기물이 있으면 못 지나감(장애물 체크). | +| **포(包)** | 상하좌우로 다른 기물 하나를 뛰어넘어 거리 제한 없이 이동 | 대각선 선을 따라 기물 하나를 넘어서 이동 | 포끼리는 서로 넘을 수 없다.
포끼리는 잡을 수 없다.
넘을 기물이 반드시 1개 있어야 함. | +| **마(馬)** | 상하좌우 직선 1칸 + 이동한 방향으로 대각선 1칸 | 해당 없음 | 멱(길목)이 막혀 있으면 못 감. | +| **상(象)** | 직선 1칸 + 이동한 방향으로 대각선 2칸 | 해당 없음 | 멱(길목)이 막혀 있으면 못 감. | +| **졸/병(卒/兵)** | 앞 또는 옆으로 1칸 | 적군 궁성 내에서 대각선 앞으로 1칸 이동 가능 | 진영에 따라 '앞'의 방향이 다름.
뒤로는 못감 | + +### 게임 종료 + +- 외통수이면 승리한다. +- 빅장이면 점수를 계산해 승패를 결정한다. +- 한나라에 1.5점을 더해서 점수를 계산한다. + +## 입력 + +- 초나라가 기물을 선택하고 행마를 입력한다. + + ```text + 초나라 턴입니다. 원하는 기물과 이동방향을 입력하세요. (예 : 포, 3, 3) + ``` + +- 한나라가 기물을 선택하고 행마를 입력한다. + + ```text + 한나라 턴입니다. 원하는 기물과 이동방향을 입력하세요. (예 : 포, 3, 3) + ``` + +## 출력 + +- 보드판을 출력한다. + + ```text + 게임을 시작하겠습니다. + + 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 + 丨 一 十 一 十 一 十 一 漢 一 十 一 十 一 十 一 丨 + 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 + 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 + 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 + 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 + 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 + 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 + 丨 一 十 一 十 一 十 一 楚 一 十 一 十 一 十 一 丨 + 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 + ``` + +- 장군이면 장군을 출력한다. + + ```text + 장군입니다! 기물을 움직여 궁을 살리세요. + ``` + +- 외통이면 게임 종료를 출력한다. + + ```text + 외통입니다. 초나라/한나라의 승리입니다. + ``` + +- 빅장이면 상대방이 선택할 수 있게 조건을 출력한다. + + ```text + 빅장입니다. 게임을 종료하기 싫으면 왕 앞에 기물을 놔두세요! + ``` + +- 빅장으로 게임이 종료되면 점수를 출력한다. + + ```text + 빅장입니다. + + 초나라 점수 : + 한나라 점수 : + + 결과 : 초나라/한나라의 승리입니다. + ``` From 5a2c00910af9878e51689664373595aa67bf5062 Mon Sep 17 00:00:00 2001 From: smiinii Date: Wed, 25 Mar 2026 16:48:23 +0900 Subject: [PATCH 02/70] =?UTF-8?q?feat:=20Position=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=BA=90=EC=8B=B1?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/.gitkeep | 0 src/main/java/janggi/domain/Position.java | 45 +++++++++++++++++++++++ src/test/java/.gitkeep | 0 3 files changed, 45 insertions(+) delete mode 100644 src/main/java/.gitkeep create mode 100644 src/main/java/janggi/domain/Position.java delete mode 100644 src/test/java/.gitkeep diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java new file mode 100644 index 0000000000..14979910f9 --- /dev/null +++ b/src/main/java/janggi/domain/Position.java @@ -0,0 +1,45 @@ +package janggi.domain; + +import janggi.exception.BoardOutOfRangeException; + +import java.util.HashMap; +import java.util.Map; + +public class Position { + private static final int MIN_X = 0; + private static final int MAX_X = 8; + private static final int MIN_Y = 0; + private static final int MAX_Y = 9; + + private static final Map CACHE = new HashMap<>(); + + static { + for (int x = MIN_X; x <= MAX_X; x++) { + for (int y = MIN_Y; y <= MAX_Y; y++) { + CACHE.put(toKey(x, y), new Position(x, y)); + } + } + } + + private final int x; + private final int y; + + private Position(int x, int y) { + this.x = x; + this.y = y; + } + + public static Position of(int x, int y) { + String key = toKey(x, y); + + if (!CACHE.containsKey(key)) { + throw new BoardOutOfRangeException(); + } + + return CACHE.get(key); + } + + private static String toKey(int x, int y) { + return x + "," + y; + } +} diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 From 9d73439e2da45872171bce07bdf609c467f5a787 Mon Sep 17 00:00:00 2001 From: smiinii Date: Wed, 25 Mar 2026 16:48:38 +0900 Subject: [PATCH 03/70] =?UTF-8?q?test:=20Position=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/PositionTest.java | 41 +++++++++++++++++++ 1 file changed, 41 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..08c39cc765 --- /dev/null +++ b/src/test/java/janggi/domain/PositionTest.java @@ -0,0 +1,41 @@ +package janggi.domain; + +import janggi.exception.BoardOutOfRangeException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + + +class PositionTest { + + @Test + void 장기판에_모든_좌표가_생성된다() { + // when & then + for (int x = 0; x <= 8; x++) { + for(int y = 0; y <= 9; y++) { + + Position position1 = Position.of(x, y); + Position position2 = Position.of(x, y); + + assertThat(position1) + .as("x=%d, y=%d 에서 캐싱 실패", x, y) + .isSameAs(position2); + } + } + } + + @ParameterizedTest + @CsvSource({ + "-1, 0", "9, 0", + "0, -1", "0, 10", + "-1, -1", "9, 10" + }) + void 장기판_범위를_벗어나면_예외가_발생한다(int x, int y) { + // when & then + assertThatThrownBy(() -> Position.of(x, y)).isInstanceOf(BoardOutOfRangeException.class); + } + +} From 426ad7feb3d523fe8035ae81ba6b0a0ea4a508fc Mon Sep 17 00:00:00 2001 From: smiinii Date: Wed, 25 Mar 2026 16:48:55 +0900 Subject: [PATCH 04/70] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/exception/BoardOutOfRangeException.java | 7 +++++++ src/main/java/janggi/exception/BusinessException.java | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 src/main/java/janggi/exception/BoardOutOfRangeException.java create mode 100644 src/main/java/janggi/exception/BusinessException.java diff --git a/src/main/java/janggi/exception/BoardOutOfRangeException.java b/src/main/java/janggi/exception/BoardOutOfRangeException.java new file mode 100644 index 0000000000..0161b746b8 --- /dev/null +++ b/src/main/java/janggi/exception/BoardOutOfRangeException.java @@ -0,0 +1,7 @@ +package janggi.exception; + +public class BoardOutOfRangeException extends BusinessException { + public BoardOutOfRangeException() { + super("장기판 범위를 벗어난 좌표입니다."); + } +} diff --git a/src/main/java/janggi/exception/BusinessException.java b/src/main/java/janggi/exception/BusinessException.java new file mode 100644 index 0000000000..5c412dff5d --- /dev/null +++ b/src/main/java/janggi/exception/BusinessException.java @@ -0,0 +1,7 @@ +package janggi.exception; + +public class BusinessException extends RuntimeException { + public BusinessException(String message) { + super("[ERROR] " + message); + } +} From 0932e8fde84b6658b8569cd18b9d60ba1163c76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Wed, 25 Mar 2026 19:43:43 +0900 Subject: [PATCH 05/70] =?UTF-8?q?docs(README):=20=EB=A6=AC=EB=93=9C?= =?UTF-8?q?=EB=AF=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 135 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index e9ca96dfd2..c01d42cc99 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,110 @@ # java-janggi +# 기능 명세서 + +--- + ## 기능 ### 게임 초기화 -- 한나라가 위, 초나라를 아래로 위치시켜 보드를 초기화한다. +- [ ] 한나라가 위, 초나라를 아래로 위치시켜 보드를 초기화한다. ### 게임 진행 -- 초나라 선, 한나라 후로 게임이 반복적으로 진행된다. -- 입력을 받은 좌표와 기물 규칙에 따라 기물을 이동시킨다. -- 궁을 잡는 수를 두면 장군이다. -- 장군을 피하는 수를 두면 멍군이다. -- 빅장일 때 게임을 종료하기 싫으면 빅장을 깨뜨리는 수를 둘 수 있다. +- [ ] 초나라 선, 한나라 후로 게임이 반복적으로 진행된다. +- [ ] 입력을 받은 좌표와 기물 규칙에 따라 기물을 이동시킨다. +- [ ] 궁을 잡는 수를 두면 장군이다. +- [ ] 장군을 피하는 수를 두면 멍군이다. +- [ ] 빅장일 때 게임을 종료하기 싫으면 빅장을 깨뜨리는 수를 둘 수 있다. ### 기물 이동 규칙 -| **기물** | **기본 이동 방식** | **궁성(3x3) 내 특수 규칙** | **특징 (구현 시 고려사항)** | -| --- | --- | --- | --- | -| **궁(將/楚)** | 상하좌우 1칸 | 대각선 선을 따라 1칸 이동 가능 | 궁성 밖으로 절대 나갈 수 없음. | -| **사(士)** | 상하좌우 1칸 | 대각선 선을 따라 1칸 이동 가능 | 궁성 밖으로 절대 나갈 수 없음. | -| **차(車)** | 상하좌우 직선으로 거리 제한 없이 이동 | 대각선 선을 따라 이동 가능 | 경로에 다른 기물이 있으면 못 지나감(장애물 체크). | -| **포(包)** | 상하좌우로 다른 기물 하나를 뛰어넘어 거리 제한 없이 이동 | 대각선 선을 따라 기물 하나를 넘어서 이동 | 포끼리는 서로 넘을 수 없다.
포끼리는 잡을 수 없다.
넘을 기물이 반드시 1개 있어야 함. | -| **마(馬)** | 상하좌우 직선 1칸 + 이동한 방향으로 대각선 1칸 | 해당 없음 | 멱(길목)이 막혀 있으면 못 감. | -| **상(象)** | 직선 1칸 + 이동한 방향으로 대각선 2칸 | 해당 없음 | 멱(길목)이 막혀 있으면 못 감. | -| **졸/병(卒/兵)** | 앞 또는 옆으로 1칸 | 적군 궁성 내에서 대각선 앞으로 1칸 이동 가능 | 진영에 따라 '앞'의 방향이 다름.
뒤로는 못감 | +| **기물** | **기본 이동 방식** | **궁성(3x3) 내 특수 규칙** | **특징 (구현 시 고려사항)** | +| --- |----------------------------------| --- |----------------------------------------------------------| +| **궁(將/楚)** | 상하좌우 1칸 | 대각선 선을 따라 1칸 이동 가능 | 궁성 밖으로 절대 나갈 수 없음 | +| **사(士)** | 상하좌우 1칸 | 대각선 선을 따라 1칸 이동 가능 | 궁성 밖으로 절대 나갈 수 없음 | +| **차(車)** | 상하좌우 직선으로 거리 제한 없이 이동 | 대각선 선을 따라 이동 가능 | 경로에 다른 기물이 있으면 못 지나감 | +| **포(包)** | 상하좌우로 다른 기물 하나를 뛰어넘어 거리 제한 없이 이동 | 대각선 선을 따라 기물 하나를 넘어서 이동 | 포끼리는 서로 넘을 수 없음
포끼리는 잡을 수 없음
넘을 기물이 반드시 1개 있어야 함 | +| **마(馬)** | 상하좌우 직선 1칸 + 이동한 방향으로 대각선 1칸 | 해당 없음 | 멱(길목)이 막혀 있으면 못 감 | +| **상(象)** | 상하좌우 직선 1칸 + 이동한 방향으로 대각선 2칸 | 해당 없음 | 멱(길목)이 막혀 있으면 못 감 | +| **졸/병(卒/兵)** | 앞 또는 옆으로 1칸 | 적군 궁성 내에서 대각선 앞으로 1칸 이동 가능 | 진영에 따라 '앞'의 방향이 다름
뒤로는 못감 | ### 게임 종료 -- 외통수이면 승리한다. -- 빅장이면 점수를 계산해 승패를 결정한다. -- 한나라에 1.5점을 더해서 점수를 계산한다. +- [ ] 외통수이면 승리한다. +- [ ] 빅장이면 점수를 계산해 승패를 결정한다. +- [ ] 한나라에 1.5점을 더해서 점수를 계산한다. ## 입력 -- 초나라가 기물을 선택하고 행마를 입력한다. +- [ ] 초나라가 기물을 선택하고 행마를 입력한다. + + ```java + 초나라 턴입니다. 이동할 기물의 좌표와 도착할 좌표를 입력하세요. (예 : (1, 2), (3, 3)) + ``` - ```text - 초나라 턴입니다. 원하는 기물과 이동방향을 입력하세요. (예 : 포, 3, 3) - ``` +- [ ] 한나라가 기물을 선택하고 행마를 입력한다. -- 한나라가 기물을 선택하고 행마를 입력한다. + ```java + 한나라 턴입니다. 이동할 기물의 좌표와 도착할 좌표를 입력하세요. (예 : (1, 2), (3, 3)) + ``` - ```text - 한나라 턴입니다. 원하는 기물과 이동방향을 입력하세요. (예 : 포, 3, 3) - ``` ## 출력 -- 보드판을 출력한다. +- [ ] 보드판을 출력한다. + + ```java + 게임을 시작하겠습니다. + + 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 + 丨 一 十 一 十 一 十 一 漢 一 十 一 十 一 十 一 丨 + 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 + 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 + 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 + 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 + 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 + 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 + 丨 一 十 一 十 一 十 一 漢 一 十 一 十 一 十 一 丨 + 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 + ``` + +- [ ] 장군이면 장군을 출력한다. - ```text - 게임을 시작하겠습니다. - - 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 - 丨 一 十 一 十 一 十 一 漢 一 十 一 十 一 十 一 丨 - 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 - 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 - 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 - 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 - 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 - 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 - 丨 一 十 一 十 一 十 一 楚 一 十 一 十 一 十 一 丨 - 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 - ``` + ```java + 장군입니다! 기물을 움직여 궁을 살리세요. + ``` -- 장군이면 장군을 출력한다. +- [ ] 외통이면 게임 종료를 출력한다. - ```text - 장군입니다! 기물을 움직여 궁을 살리세요. - ``` + ```java + 외통입니다. 초나라/한나라의 승리입니다. + ``` -- 외통이면 게임 종료를 출력한다. +- [ ] 빅장이면 상대방이 선택할 수 있게 조건을 출력한다. - ```text - 외통입니다. 초나라/한나라의 승리입니다. - ``` + ```java + 빅장입니다. 게임을 종료하기 싫으면 왕 앞에 기물을 놔두세요! + ``` -- 빅장이면 상대방이 선택할 수 있게 조건을 출력한다. +- [ ] 빅장으로 게임이 종료되면 점수를 출력한다. - ```text - 빅장입니다. 게임을 종료하기 싫으면 왕 앞에 기물을 놔두세요! - ``` + ```java + 빅장입니다. + + 초나라 점수 : + 한나라 점수 : + + 결과 : 초나라/한나라의 승리입니다. + ``` -- 빅장으로 게임이 종료되면 점수를 출력한다. - ```text - 빅장입니다. +## 유효성 - 초나라 점수 : - 한나라 점수 : +### Position - 결과 : 초나라/한나라의 승리입니다. - ``` +- [x] 장기판 범위를 벗어난 경우 + ```java + [ERROR] 장기판 범위를 벗어난 좌표입니다. + ``` \ No newline at end of file From 95e0e561b634a926ffb5ab1cd11d55bf7f6dc587 Mon Sep 17 00:00:00 2001 From: smiinii Date: Wed, 25 Mar 2026 19:48:42 +0900 Subject: [PATCH 06/70] =?UTF-8?q?style:=20README=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=9D=98=20=EB=A7=88=EC=A7=80=EB=A7=89=20=EC=A4=84=20=EA=B0=9C?= =?UTF-8?q?=ED=96=89=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c01d42cc99..6a052d0f6b 100644 --- a/README.md +++ b/README.md @@ -107,4 +107,4 @@ - [x] 장기판 범위를 벗어난 경우 ```java [ERROR] 장기판 범위를 벗어난 좌표입니다. - ``` \ No newline at end of file + ``` From 860154567803d5743eb9c930ba3bc34892e5d6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Thu, 26 Mar 2026 11:17:11 +0900 Subject: [PATCH 07/70] =?UTF-8?q?test:=20row,=20col=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/ColumnTest.java | 30 +++++++++++++++++++++ src/test/java/janggi/domain/RowTest.java | 29 ++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/test/java/janggi/domain/ColumnTest.java create mode 100644 src/test/java/janggi/domain/RowTest.java diff --git a/src/test/java/janggi/domain/ColumnTest.java b/src/test/java/janggi/domain/ColumnTest.java new file mode 100644 index 0000000000..f398cb8d2e --- /dev/null +++ b/src/test/java/janggi/domain/ColumnTest.java @@ -0,0 +1,30 @@ +package janggi.domain; + + +import janggi.exception.ColumnOutOfRangeException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class ColumnTest { + @Test + void 장기판의_y좌표_범위를_벗어나면_예외가_발생한다() { + Assertions.assertThatThrownBy(() -> Column.of(11)).isInstanceOf(ColumnOutOfRangeException.class); + Assertions.assertThatThrownBy(() -> Column.of(-1)).isInstanceOf(ColumnOutOfRangeException.class); + } + + @Test + void 장기판의_y좌표_범위_내라면_예외가_발생하지_않는다() { + Column column1 = Column.of(1); + Column column2 = Column.of(10); + + Assertions.assertThat(column1.getColumn()).isEqualTo(1); + Assertions.assertThat(column2.getColumn()).isEqualTo(10); + } + + @Test + void 동등성_테스트() { + Column column = Column.of(1); + + Assertions.assertThat(column).isEqualTo(Column.of(1)); + } +} diff --git a/src/test/java/janggi/domain/RowTest.java b/src/test/java/janggi/domain/RowTest.java new file mode 100644 index 0000000000..33361866e8 --- /dev/null +++ b/src/test/java/janggi/domain/RowTest.java @@ -0,0 +1,29 @@ +package janggi.domain; + +import janggi.exception.RowOutOfRangeException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class RowTest { + @Test + void 장기판의_x좌표_범위를_벗어나면_예외가_발생한다() { + Assertions.assertThatThrownBy(() -> Row.of(10)).isInstanceOf(RowOutOfRangeException.class); + Assertions.assertThatThrownBy(() -> Row.of(0)).isInstanceOf(RowOutOfRangeException.class); + } + + @Test + void 장기판의_x좌표_범위_내라면_예외가_발생하지_않는다() { + Row row1 = Row.of(1); + Row row2 = Row.of(9); + + Assertions.assertThat(row1.getRow()).isEqualTo(1); + Assertions.assertThat(row2.getRow()).isEqualTo(9); + } + + @Test + void 동등성_테스트() { + Row row = Row.of(1); + + Assertions.assertThat(row).isEqualTo(Row.of(1)); + } +} From a135b2c72ee434789bf1102e4b226dbf82ee0353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Thu, 26 Mar 2026 11:18:06 +0900 Subject: [PATCH 08/70] =?UTF-8?q?feat:=20Row,=20Column=20=EA=B0=92=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=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/Column.java | 54 +++++++++++++++++++++++++ src/main/java/janggi/domain/Row.java | 54 +++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/main/java/janggi/domain/Column.java create mode 100644 src/main/java/janggi/domain/Row.java diff --git a/src/main/java/janggi/domain/Column.java b/src/main/java/janggi/domain/Column.java new file mode 100644 index 0000000000..ff4f349fad --- /dev/null +++ b/src/main/java/janggi/domain/Column.java @@ -0,0 +1,54 @@ +package janggi.domain; + +import janggi.exception.ColumnOutOfRangeException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class Column { + private static final int MIN = 1; + private static final int MAX = 10; + private static final Map CACHE = new HashMap<>(); + + static { + for (int i = MIN; i <= MAX; i++) { + CACHE.put(i, new Column(i)); + } + } + + private final int value; + + private Column(int value) { + this.value = value; + } + public static Column of(int value) { + if (!CACHE.containsKey(value)) { + throw new ColumnOutOfRangeException(); + } + return CACHE.get(value); + } + + public static Collection values() { + return CACHE.values(); + } + + public int getColumn() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + Column column = (Column) o; + return this.value == column.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/src/main/java/janggi/domain/Row.java b/src/main/java/janggi/domain/Row.java new file mode 100644 index 0000000000..487a49e746 --- /dev/null +++ b/src/main/java/janggi/domain/Row.java @@ -0,0 +1,54 @@ +package janggi.domain; + +import janggi.exception.RowOutOfRangeException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class Row { + private static final int MIN = 1; + private static final int MAX = 9; + private static final Map CACHE = new HashMap<>(); + + static { + for (int i = MIN; i <= MAX; i++) { + CACHE.put(i, new Row(i)); + } + } + + private final int value; + + private Row(int value) { + this.value = value; + } + public static Row of(int value) { + if (!CACHE.containsKey(value)) { + throw new RowOutOfRangeException(); + } + return CACHE.get(value); + } + + public static Collection values() { + return CACHE.values(); + } + + public int getRow() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + Row row = (Row) o; + return this.value == row.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} From 5fcf6beac52fcffc799467142efa2469af6c9d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Thu, 26 Mar 2026 11:19:00 +0900 Subject: [PATCH 09/70] =?UTF-8?q?feat:=20Row,=20Column=20=EB=B2=94?= =?UTF-8?q?=EC=9C=84=20=EC=98=88=EC=99=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/exception/BoardOutOfRangeException.java | 7 ------- .../java/janggi/exception/ColumnOutOfRangeException.java | 7 +++++++ src/main/java/janggi/exception/RowOutOfRangeException.java | 7 +++++++ 3 files changed, 14 insertions(+), 7 deletions(-) delete mode 100644 src/main/java/janggi/exception/BoardOutOfRangeException.java create mode 100644 src/main/java/janggi/exception/ColumnOutOfRangeException.java create mode 100644 src/main/java/janggi/exception/RowOutOfRangeException.java diff --git a/src/main/java/janggi/exception/BoardOutOfRangeException.java b/src/main/java/janggi/exception/BoardOutOfRangeException.java deleted file mode 100644 index 0161b746b8..0000000000 --- a/src/main/java/janggi/exception/BoardOutOfRangeException.java +++ /dev/null @@ -1,7 +0,0 @@ -package janggi.exception; - -public class BoardOutOfRangeException extends BusinessException { - public BoardOutOfRangeException() { - super("장기판 범위를 벗어난 좌표입니다."); - } -} diff --git a/src/main/java/janggi/exception/ColumnOutOfRangeException.java b/src/main/java/janggi/exception/ColumnOutOfRangeException.java new file mode 100644 index 0000000000..6e5449bb10 --- /dev/null +++ b/src/main/java/janggi/exception/ColumnOutOfRangeException.java @@ -0,0 +1,7 @@ +package janggi.exception; + +public class ColumnOutOfRangeException extends BusinessException { + public ColumnOutOfRangeException() { + super("장기판의 y좌표 범위를 벗어났습니다."); + } +} diff --git a/src/main/java/janggi/exception/RowOutOfRangeException.java b/src/main/java/janggi/exception/RowOutOfRangeException.java new file mode 100644 index 0000000000..b9a7b411f6 --- /dev/null +++ b/src/main/java/janggi/exception/RowOutOfRangeException.java @@ -0,0 +1,7 @@ +package janggi.exception; + +public class RowOutOfRangeException extends BusinessException { + public RowOutOfRangeException() { + super("장기판의 x좌표 범위를 벗어났습니다."); + } +} From de86e2493ca199c66b980c19e6e62cb48615b124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Thu, 26 Mar 2026 11:19:36 +0900 Subject: [PATCH 10/70] =?UTF-8?q?test:=20Position=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/PositionTest.java | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/test/java/janggi/domain/PositionTest.java b/src/test/java/janggi/domain/PositionTest.java index 08c39cc765..de9643389b 100644 --- a/src/test/java/janggi/domain/PositionTest.java +++ b/src/test/java/janggi/domain/PositionTest.java @@ -1,12 +1,8 @@ package janggi.domain; -import janggi.exception.BoardOutOfRangeException; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; class PositionTest { @@ -14,11 +10,11 @@ class PositionTest { @Test void 장기판에_모든_좌표가_생성된다() { // when & then - for (int x = 0; x <= 8; x++) { - for(int y = 0; y <= 9; y++) { + for (int x = 1; x <= 9; x++) { + for(int y = 1; y <= 10; y++) { - Position position1 = Position.of(x, y); - Position position2 = Position.of(x, y); + Position position1 = Position.of(Row.of(x), Column.of(y)); + Position position2 = Position.of(Row.of(x), Column.of(y)); assertThat(position1) .as("x=%d, y=%d 에서 캐싱 실패", x, y) @@ -26,16 +22,4 @@ class PositionTest { } } } - - @ParameterizedTest - @CsvSource({ - "-1, 0", "9, 0", - "0, -1", "0, 10", - "-1, -1", "9, 10" - }) - void 장기판_범위를_벗어나면_예외가_발생한다(int x, int y) { - // when & then - assertThatThrownBy(() -> Position.of(x, y)).isInstanceOf(BoardOutOfRangeException.class); - } - } From 8112d42e0904941c428093ad7d7dd46ffd54b21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Thu, 26 Mar 2026 11:22:33 +0900 Subject: [PATCH 11/70] =?UTF-8?q?refactor:=20Row,=20Column=20=EA=B0=92?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EB=B3=80=EA=B2=BD=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B8=ED=95=9C=20Position=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 | 31 ++++++++--------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 14979910f9..3aa3f9fab4 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -1,45 +1,34 @@ package janggi.domain; -import janggi.exception.BoardOutOfRangeException; - import java.util.HashMap; import java.util.Map; public class Position { - private static final int MIN_X = 0; - private static final int MAX_X = 8; - private static final int MIN_Y = 0; - private static final int MAX_Y = 9; - private static final Map CACHE = new HashMap<>(); static { - for (int x = MIN_X; x <= MAX_X; x++) { - for (int y = MIN_Y; y <= MAX_Y; y++) { - CACHE.put(toKey(x, y), new Position(x, y)); + for (Row row : Row.values()) { + for (Column column : Column.values()) { + CACHE.put(toKey(row, column), new Position(row, column)); } + } } - private final int x; - private final int y; + private final Row x; + private final Column y; - private Position(int x, int y) { + private Position(Row x, Column y) { this.x = x; this.y = y; } - public static Position of(int x, int y) { + public static Position of(Row x, Column y) { String key = toKey(x, y); - - if (!CACHE.containsKey(key)) { - throw new BoardOutOfRangeException(); - } - return CACHE.get(key); } - private static String toKey(int x, int y) { - return x + "," + y; + private static String toKey(Row x, Column y) { + return x.getRow() + "," + y.getColumn(); } } From 228870e54bb86b94f6809459f112055f8b04e924 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 17:43:07 +0900 Subject: [PATCH 12/70] =?UTF-8?q?refactor:=20Row=20=EB=B0=8F=20Column=20?= =?UTF-8?q?=EB=B2=94=EC=9C=84=20=EC=83=81=EC=88=98=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/Column.java | 4 ++-- src/main/java/janggi/domain/Row.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/domain/Column.java b/src/main/java/janggi/domain/Column.java index ff4f349fad..68dbf0fc92 100644 --- a/src/main/java/janggi/domain/Column.java +++ b/src/main/java/janggi/domain/Column.java @@ -7,8 +7,8 @@ import java.util.Objects; public class Column { - private static final int MIN = 1; - private static final int MAX = 10; + private static final int MIN = 0; + private static final int MAX = 9; private static final Map CACHE = new HashMap<>(); static { diff --git a/src/main/java/janggi/domain/Row.java b/src/main/java/janggi/domain/Row.java index 487a49e746..fc8c790360 100644 --- a/src/main/java/janggi/domain/Row.java +++ b/src/main/java/janggi/domain/Row.java @@ -7,8 +7,8 @@ import java.util.Objects; public class Row { - private static final int MIN = 1; - private static final int MAX = 9; + private static final int MIN = 0; + private static final int MAX = 8; private static final Map CACHE = new HashMap<>(); static { From ddde159c262df68c394baf61be30b4a17f5bf9d9 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 17:43:19 +0900 Subject: [PATCH 13/70] =?UTF-8?q?test:=20Row=20=EB=B0=8F=20Column=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/ColumnTest.java | 10 +++++----- src/test/java/janggi/domain/RowTest.java | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/test/java/janggi/domain/ColumnTest.java b/src/test/java/janggi/domain/ColumnTest.java index f398cb8d2e..f59872ca4d 100644 --- a/src/test/java/janggi/domain/ColumnTest.java +++ b/src/test/java/janggi/domain/ColumnTest.java @@ -8,17 +8,17 @@ class ColumnTest { @Test void 장기판의_y좌표_범위를_벗어나면_예외가_발생한다() { - Assertions.assertThatThrownBy(() -> Column.of(11)).isInstanceOf(ColumnOutOfRangeException.class); + Assertions.assertThatThrownBy(() -> Column.of(10)).isInstanceOf(ColumnOutOfRangeException.class); Assertions.assertThatThrownBy(() -> Column.of(-1)).isInstanceOf(ColumnOutOfRangeException.class); } @Test void 장기판의_y좌표_범위_내라면_예외가_발생하지_않는다() { - Column column1 = Column.of(1); - Column column2 = Column.of(10); + Column column1 = Column.of(0); + Column column2 = Column.of(9); - Assertions.assertThat(column1.getColumn()).isEqualTo(1); - Assertions.assertThat(column2.getColumn()).isEqualTo(10); + Assertions.assertThat(column1.getColumn()).isEqualTo(0); + Assertions.assertThat(column2.getColumn()).isEqualTo(9); } @Test diff --git a/src/test/java/janggi/domain/RowTest.java b/src/test/java/janggi/domain/RowTest.java index 33361866e8..0c8c3dfa3a 100644 --- a/src/test/java/janggi/domain/RowTest.java +++ b/src/test/java/janggi/domain/RowTest.java @@ -7,17 +7,17 @@ class RowTest { @Test void 장기판의_x좌표_범위를_벗어나면_예외가_발생한다() { - Assertions.assertThatThrownBy(() -> Row.of(10)).isInstanceOf(RowOutOfRangeException.class); - Assertions.assertThatThrownBy(() -> Row.of(0)).isInstanceOf(RowOutOfRangeException.class); + Assertions.assertThatThrownBy(() -> Row.of(9)).isInstanceOf(RowOutOfRangeException.class); + Assertions.assertThatThrownBy(() -> Row.of(-1)).isInstanceOf(RowOutOfRangeException.class); } @Test void 장기판의_x좌표_범위_내라면_예외가_발생하지_않는다() { - Row row1 = Row.of(1); - Row row2 = Row.of(9); + Row row1 = Row.of(0); + Row row2 = Row.of(8); - Assertions.assertThat(row1.getRow()).isEqualTo(1); - Assertions.assertThat(row2.getRow()).isEqualTo(9); + Assertions.assertThat(row1.getRow()).isEqualTo(0); + Assertions.assertThat(row2.getRow()).isEqualTo(8); } @Test From ddb05a606a081ddcc53843dadbf74d7d5cb0868e Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 17:43:25 +0900 Subject: [PATCH 14/70] =?UTF-8?q?style:=20Position=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=82=B4=EB=B6=80=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B3=B5=EB=B0=B1=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 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 3aa3f9fab4..e6adae8fa5 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -11,7 +11,6 @@ public class Position { for (Column column : Column.values()) { CACHE.put(toKey(row, column), new Position(row, column)); } - } } From cc341de3cee64fa1d4f6664d4e82f5871a2e8725 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:22:45 +0900 Subject: [PATCH 15/70] =?UTF-8?q?feat:=20Position=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EC=A2=8C=ED=91=9C=20=EB=B0=98=ED=99=98=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Position.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index e6adae8fa5..02ec16790a 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -1,6 +1,8 @@ package janggi.domain; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class Position { @@ -30,4 +32,11 @@ public static Position of(Row x, Column y) { private static String toKey(Row x, Column y) { return x.getRow() + "," + y.getColumn(); } + + public List getPosition() { + List position = new ArrayList<>(); + position.add(x.getRow()); + position.add(y.getColumn()); + return position; + } } From 5522e54568678174c8675e0677277b501b5d4503 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:28:26 +0900 Subject: [PATCH 16/70] =?UTF-8?q?feat:=20Board=20=EB=B0=8F=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardFactory.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/main/java/janggi/domain/BoardFactory.java diff --git a/src/main/java/janggi/domain/BoardFactory.java b/src/main/java/janggi/domain/BoardFactory.java new file mode 100644 index 0000000000..0db5569594 --- /dev/null +++ b/src/main/java/janggi/domain/BoardFactory.java @@ -0,0 +1,106 @@ +package janggi.domain; + +import janggi.domain.movestorage.ChaMoveStorage; +import janggi.domain.movestorage.GungMoveStorage; +import janggi.domain.movestorage.JolMoveStorage; +import janggi.domain.movestorage.MaMoveStorage; +import janggi.domain.movestorage.SaMoveStorage; +import janggi.domain.movestorage.SangMoveStorage; + +import java.util.HashMap; +import java.util.Map; + +public class BoardFactory { + public static Map generate() { + Map board = new HashMap<>(); + + SetHanPieces(board); + SetChoPieces(board); + + return board; + } + + private static void SetHanPieces(Map board) { + // 차 + board.put(Position.of(Row.of(0), Column.of(0)), + new Piece(new ChaMoveStorage(), Team.HAN, 13, "車")); + board.put(Position.of(Row.of(8), Column.of(0)), + new Piece(new ChaMoveStorage(), Team.HAN, 13, "車")); + // 상 + board.put(Position.of(Row.of(1), Column.of(0)), + new Piece(new SangMoveStorage(), Team.HAN, 3, "象")); + board.put(Position.of(Row.of(6), Column.of(0)), + new Piece(new SangMoveStorage(), Team.HAN, 3, "象")); + // 마 + board.put(Position.of(Row.of(2), Column.of(0)), + new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); + board.put(Position.of(Row.of(7), Column.of(0)), + new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); + // 사 + board.put(Position.of(Row.of(3), Column.of(0)), + new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + board.put(Position.of(Row.of(5), Column.of(0)), + new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + // 궁 + board.put(Position.of(Row.of(4), Column.of(1)), + new Piece(new GungMoveStorage(), Team.HAN, 0, "漢")); + // 포 + board.put(Position.of(Row.of(1), Column.of(2)), + new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + board.put(Position.of(Row.of(7), Column.of(2)), + new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + // 졸 + board.put(Position.of(Row.of(0), Column.of(3)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "兵")); + board.put(Position.of(Row.of(2), Column.of(3)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "兵")); + board.put(Position.of(Row.of(4), Column.of(3)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "兵")); + board.put(Position.of(Row.of(6), Column.of(3)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "兵")); + board.put(Position.of(Row.of(8), Column.of(3)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "兵")); + } + + private static void SetChoPieces(Map board) { + // 차 + board.put(Position.of(Row.of(0), Column.of(9)), + new Piece(new ChaMoveStorage(), Team.HAN, 13, "車")); + board.put(Position.of(Row.of(8), Column.of(9)), + new Piece(new ChaMoveStorage(), Team.HAN, 13, "車")); + // 상 + board.put(Position.of(Row.of(1), Column.of(9)), + new Piece(new SangMoveStorage(), Team.HAN, 3, "象")); + board.put(Position.of(Row.of(6), Column.of(9)), + new Piece(new SangMoveStorage(), Team.HAN, 3, "象")); + // 마 + board.put(Position.of(Row.of(2), Column.of(9)), + new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); + board.put(Position.of(Row.of(7), Column.of(9)), + new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); + // 사 + board.put(Position.of(Row.of(3), Column.of(9)), + new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + board.put(Position.of(Row.of(5), Column.of(9)), + new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + // 궁 + board.put(Position.of(Row.of(4), Column.of(8)), + new Piece(new GungMoveStorage(), Team.HAN, 0, "楚")); + // 포 + board.put(Position.of(Row.of(1), Column.of(7)), + new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + board.put(Position.of(Row.of(7), Column.of(7)), + new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + // 졸 + board.put(Position.of(Row.of(0), Column.of(6)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + board.put(Position.of(Row.of(2), Column.of(6)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + board.put(Position.of(Row.of(4), Column.of(6)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + board.put(Position.of(Row.of(6), Column.of(6)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + board.put(Position.of(Row.of(8), Column.of(6)), + new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + } +} From d889e9cfec0001d795bff6d19318870dc8108cd6 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:32:57 +0900 Subject: [PATCH 17/70] =?UTF-8?q?feat:=20Piece=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Piece.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/janggi/domain/Piece.java diff --git a/src/main/java/janggi/domain/Piece.java b/src/main/java/janggi/domain/Piece.java new file mode 100644 index 0000000000..027988e7fe --- /dev/null +++ b/src/main/java/janggi/domain/Piece.java @@ -0,0 +1,25 @@ +package janggi.domain; + +import janggi.domain.movestorage.MoveStorage; + +public class Piece { + private final MoveStorage moveStorage; + private final Team team; + private final int score; + private final String name; + + public Piece(MoveStorage moveStorage, Team team, int score, String name) { + this.moveStorage = moveStorage; + this.team = team; + this.score = score; + this.name = name; + } + // TODO: 이동가능 여부 구현 (2026. 3. 26.) + public void verifyMove(Position from, Position to, BoardState boardState) { + + } + + public String getName() { + return name; + } +} From 00ddeddd451f5d5116e857074653db58962192fb Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:33:08 +0900 Subject: [PATCH 18/70] =?UTF-8?q?feat:=20MoveStorage=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/movestorage/MoveStorage.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/janggi/domain/movestorage/MoveStorage.java diff --git a/src/main/java/janggi/domain/movestorage/MoveStorage.java b/src/main/java/janggi/domain/movestorage/MoveStorage.java new file mode 100644 index 0000000000..7068b24ff6 --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/MoveStorage.java @@ -0,0 +1,8 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public interface MoveStorage { + boolean canMove(Position from, Position to, BoardState boardState); +} From 02914c179c64ac115443a355638fa30fb503b12f Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:33:28 +0900 Subject: [PATCH 19/70] =?UTF-8?q?feat:=20=EA=B0=81=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EC=9D=98=20MoveStorage=20=ED=81=B4=EB=9E=98=EC=8A=A4=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 --- .../janggi/domain/movestorage/ChaMoveStorage.java | 12 ++++++++++++ .../janggi/domain/movestorage/GungMoveStorage.java | 12 ++++++++++++ .../janggi/domain/movestorage/JolMoveStorage.java | 12 ++++++++++++ .../janggi/domain/movestorage/MaMoveStorage.java | 12 ++++++++++++ .../janggi/domain/movestorage/PoMoveStorage.java | 12 ++++++++++++ .../janggi/domain/movestorage/SaMoveStorage.java | 12 ++++++++++++ .../janggi/domain/movestorage/SangMoveStorage.java | 12 ++++++++++++ 7 files changed, 84 insertions(+) create mode 100644 src/main/java/janggi/domain/movestorage/ChaMoveStorage.java create mode 100644 src/main/java/janggi/domain/movestorage/GungMoveStorage.java create mode 100644 src/main/java/janggi/domain/movestorage/JolMoveStorage.java create mode 100644 src/main/java/janggi/domain/movestorage/MaMoveStorage.java create mode 100644 src/main/java/janggi/domain/movestorage/PoMoveStorage.java create mode 100644 src/main/java/janggi/domain/movestorage/SaMoveStorage.java create mode 100644 src/main/java/janggi/domain/movestorage/SangMoveStorage.java diff --git a/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java b/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java new file mode 100644 index 0000000000..fe79040317 --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class ChaMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} diff --git a/src/main/java/janggi/domain/movestorage/GungMoveStorage.java b/src/main/java/janggi/domain/movestorage/GungMoveStorage.java new file mode 100644 index 0000000000..0aabe4c6fd --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/GungMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class GungMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} diff --git a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java new file mode 100644 index 0000000000..7c07bb7220 --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class JolMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} diff --git a/src/main/java/janggi/domain/movestorage/MaMoveStorage.java b/src/main/java/janggi/domain/movestorage/MaMoveStorage.java new file mode 100644 index 0000000000..ae53a3a2b7 --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/MaMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class MaMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} diff --git a/src/main/java/janggi/domain/movestorage/PoMoveStorage.java b/src/main/java/janggi/domain/movestorage/PoMoveStorage.java new file mode 100644 index 0000000000..53a420590c --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/PoMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class PoMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} diff --git a/src/main/java/janggi/domain/movestorage/SaMoveStorage.java b/src/main/java/janggi/domain/movestorage/SaMoveStorage.java new file mode 100644 index 0000000000..e6031dcb82 --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/SaMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class SaMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} diff --git a/src/main/java/janggi/domain/movestorage/SangMoveStorage.java b/src/main/java/janggi/domain/movestorage/SangMoveStorage.java new file mode 100644 index 0000000000..4ea8ab5264 --- /dev/null +++ b/src/main/java/janggi/domain/movestorage/SangMoveStorage.java @@ -0,0 +1,12 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Position; + +public class SangMoveStorage implements MoveStorage{ + // TODO: 이동 규칙 구현 (2026. 3. 26.) + @Override + public boolean canMove(Position from, Position to, BoardState boardState) { + return true; + } +} From 55557b7e53252d4c17f1f3643c64bb9adda49569 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:33:48 +0900 Subject: [PATCH 20/70] =?UTF-8?q?feat:=20=ED=8C=80=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20Team=20enum=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Team.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/janggi/domain/Team.java diff --git a/src/main/java/janggi/domain/Team.java b/src/main/java/janggi/domain/Team.java new file mode 100644 index 0000000000..2a65e39c81 --- /dev/null +++ b/src/main/java/janggi/domain/Team.java @@ -0,0 +1,6 @@ +package janggi.domain; + +public enum Team { + CHO, + HAN; +} From 9979b4b00ea8be6d51b7c343207b29297a455f6d Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:33:55 +0900 Subject: [PATCH 21/70] =?UTF-8?q?feat:=20=EC=B2=B4=EC=8A=A4=ED=8C=90=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=ED=99=95=EC=9D=B8=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20BoardState=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardState.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/janggi/domain/BoardState.java diff --git a/src/main/java/janggi/domain/BoardState.java b/src/main/java/janggi/domain/BoardState.java new file mode 100644 index 0000000000..d0894f49b6 --- /dev/null +++ b/src/main/java/janggi/domain/BoardState.java @@ -0,0 +1,6 @@ +package janggi.domain; + +public interface BoardState { + boolean hasPieceAt(Position position); + Piece getPieceAt(Position position); +} From dfa00b121c91254fc0f7a886a95f34ec022ec574 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:34:08 +0900 Subject: [PATCH 22/70] =?UTF-8?q?feat:=20=EA=B8=B0=EB=AC=BC=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20=EC=B2=B4=EC=8A=A4=ED=8C=90=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B4=80=EB=A6=AC=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/domain/Board.java | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/janggi/domain/Board.java diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/Board.java new file mode 100644 index 0000000000..c2f77f7218 --- /dev/null +++ b/src/main/java/janggi/domain/Board.java @@ -0,0 +1,33 @@ +package janggi.domain; + +import java.util.HashMap; +import java.util.Map; + +public class Board implements BoardState{ + private final Map board; + + public Board(Map initialPieces) { + this.board = new HashMap<>(initialPieces); + } + + @Override + public boolean hasPieceAt(Position position) { + return board.containsKey(position); + } + + @Override + public Piece getPieceAt(Position position) { + return board.get(position); + } + + public void move(Position from, Position to) { + Piece movingPiece = board.get(from); + movingPiece.verifyMove(from, to, this); + board.remove(from); + board.put(to, movingPiece); + } + + public Map getBoard() { + return board; + } +} From d32648d730068a72afbc6ac50b4920e91d2d3ccd Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:34:15 +0900 Subject: [PATCH 23/70] =?UTF-8?q?feat:=20Board=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=EC=9D=84=20=EC=9C=84=ED=95=9C=20BoardDto=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/dto/BoardDto.java | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/janggi/dto/BoardDto.java diff --git a/src/main/java/janggi/dto/BoardDto.java b/src/main/java/janggi/dto/BoardDto.java new file mode 100644 index 0000000000..16ea8573c4 --- /dev/null +++ b/src/main/java/janggi/dto/BoardDto.java @@ -0,0 +1,31 @@ +package janggi.dto; + +import janggi.domain.Board; +import janggi.domain.Piece; +import janggi.domain.Position; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BoardDto { + private final Map, String> pieces; + + private BoardDto(Map, String> pieces) { + this.pieces = pieces; + } + + public static BoardDto from(Board board) { + Map, String> result = new HashMap<>(); + Map pieces = board.getBoard(); + + for (Position position : pieces.keySet()) { + result.put(position.getPosition(), pieces.get(position).getName()); + } + return new BoardDto(result); + } + + public Map, String> getPieces() { + return pieces; + } +} From 76b68abc17af4bd8215a14f90b9d524f4b236cdc Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:34:29 +0900 Subject: [PATCH 24/70] =?UTF-8?q?feat:=20Controller=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B0=8F=20=EA=B8=B0=EB=B3=B8=20=EC=9A=B4=EC=98=81?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/controller/Controller.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/janggi/controller/Controller.java diff --git a/src/main/java/janggi/controller/Controller.java b/src/main/java/janggi/controller/Controller.java new file mode 100644 index 0000000000..8394ea5c96 --- /dev/null +++ b/src/main/java/janggi/controller/Controller.java @@ -0,0 +1,23 @@ +package janggi.controller; + +import janggi.domain.Board; +import janggi.domain.BoardFactory; +import janggi.dto.BoardDto; +import janggi.view.InputView; +import janggi.view.OutputView; + +public class Controller { + private final InputView inputView; + private final OutputView outputView; + + public Controller(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + outputView.printStartMessage(); + Board board = new Board(BoardFactory.generate()); + outputView.printBoard(BoardDto.from(board)); + } +} From 6489109945fd663dd1fde5541d9fabdf6fd4cc30 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:34:38 +0900 Subject: [PATCH 25/70] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20InputView=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/view/InputView.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/janggi/view/InputView.java diff --git a/src/main/java/janggi/view/InputView.java b/src/main/java/janggi/view/InputView.java new file mode 100644 index 0000000000..9c383faac1 --- /dev/null +++ b/src/main/java/janggi/view/InputView.java @@ -0,0 +1,13 @@ +package janggi.view; + +import java.util.Scanner; + +public class InputView { + private final Scanner sc; + + public InputView() { + this.sc = new Scanner(System.in); + } + + +} From 70b6da28522ccbfb5d18c1fd511e28e2f1509fb3 Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:36:55 +0900 Subject: [PATCH 26/70] =?UTF-8?q?feat:=20=EC=B2=B4=EC=8A=A4=ED=8C=90=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=EC=9D=84=20=EC=9C=84=ED=95=9C=20OutputView?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/view/OutputView.java | 130 ++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/main/java/janggi/view/OutputView.java diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java new file mode 100644 index 0000000000..7b68ff4586 --- /dev/null +++ b/src/main/java/janggi/view/OutputView.java @@ -0,0 +1,130 @@ +package janggi.view; + +import janggi.dto.BoardDto; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class OutputView { + + private static final int BOARD_WIDTH = 9; + private static final int BOARD_HEIGHT = 10; + private static final int NODE_CHARS = 10; + private static final int SPACER_LINES = 3; + private static final String EMPTY_NODE = "[ ]"; + + private static final String ANSI_RED = "\u001B[31m"; + private static final String ANSI_GREEN = "\u001B[32m"; + private static final String ANSI_RESET = "\u001B[0m"; + + public void printStartMessage() { + System.out.println("게임을 시작하겠습니다."); + System.out.println(); + } + + public void printBoard(BoardDto boardDto) { + String[][] boardView = generateBoardView(boardDto); + + printXCoordinates(); + for (int y = 0; y < BOARD_HEIGHT; y++) { + printNodeRow(boardView, y); + if (y < BOARD_HEIGHT - 1) { + printSpacerRows(y); + } + } + System.out.println(); + } + + private String[][] generateBoardView(BoardDto boardDto) { + String[][] boardView = new String[BOARD_HEIGHT][BOARD_WIDTH]; + + for (int y = 0; y < BOARD_HEIGHT; y++) { + Arrays.fill(boardView[y], EMPTY_NODE); + } + + Map, String> pieces = boardDto.getPieces(); + for (Map.Entry, String> entry : pieces.entrySet()) { + List position = entry.getKey(); + int x = position.get(0); + int y = position.get(1); + String pieceName = entry.getValue(); + + String colorCode = determineFactionColor(pieceName, y); + + String formattedPiece = String.format("[%s%s%s]", colorCode, pieceName, ANSI_RESET); + boardView[y][x] = formattedPiece; + } + + return boardView; + } + + private String determineFactionColor(String pieceName, int y) { + if (pieceName.equals("漢") || pieceName.equals("兵")) { + return ANSI_RED; + } + if (pieceName.equals("楚") || pieceName.equals("卒")) { + return ANSI_GREEN; + } + + if (y <= 4) { + return ANSI_RED; + } + return ANSI_GREEN; + } + + private void printXCoordinates() { + StringBuilder xAxis = new StringBuilder(" "); + for (int x = 0; x < BOARD_WIDTH; x++) { + char fullWidthNum = (char) ('\uFF10' + x); + xAxis.append(" ").append(fullWidthNum).append(" "); + } + System.out.println(xAxis.toString()); + System.out.println(); + } + + private void printNodeRow(String[][] boardView, int y) { + StringBuilder row = new StringBuilder(); + row.append(y).append(" "); + for (int x = 0; x < BOARD_WIDTH; x++) { + row.append(boardView[y][x]); + if (x < BOARD_WIDTH - 1) { + row.append("-------"); + } + } + System.out.println(row.toString()); + } + + private void printSpacerRows(int y) { + int[] diagonalOffsets = {2, 5, 8}; + + for (int spacerIndex = 0; spacerIndex < SPACER_LINES; spacerIndex++) { + char[] spacer = new char[BOARD_WIDTH * NODE_CHARS]; + Arrays.fill(spacer, ' '); + + for (int x = 0; x < BOARD_WIDTH; x++) { + spacer[x * NODE_CHARS + 1] = 'ㅣ'; + } + + int offset = diagonalOffsets[spacerIndex]; + addPalaceDiagonals(spacer, y, offset); + + System.out.print(" "); + System.out.println(new String(spacer)); + } + } + + private void addPalaceDiagonals(char[] spacer, int y, int offset) { + int x3Center = 3 * NODE_CHARS + 1; + int x4Center = 4 * NODE_CHARS + 1; + int x5Center = 5 * NODE_CHARS + 1; + + if (y == 0 || y == 7) { + spacer[x3Center + offset] = '\\'; + spacer[x5Center - offset] = '/'; + } else if (y == 1 || y == 8) { + spacer[x4Center - offset] = '/'; + spacer[x4Center + offset] = '\\'; + } + } +} From a64c952599f0acfdc30359565301f5a764e1b6ca Mon Sep 17 00:00:00 2001 From: smiinii Date: Thu, 26 Mar 2026 21:37:09 +0900 Subject: [PATCH 27/70] =?UTF-8?q?feat:=20Application=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/Application.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/janggi/Application.java diff --git a/src/main/java/janggi/Application.java b/src/main/java/janggi/Application.java new file mode 100644 index 0000000000..c5d0e612b3 --- /dev/null +++ b/src/main/java/janggi/Application.java @@ -0,0 +1,16 @@ +package janggi; + +import janggi.controller.Controller; +import janggi.view.InputView; +import janggi.view.OutputView; + +public class Application { + public static void main(String[] args) { + + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + Controller controller = new Controller(inputView, outputView); + + controller.run(); + } +} From 201fc2e6e769f8ca54ec8bce76c7fc8c7f98e531 Mon Sep 17 00:00:00 2001 From: smiinii Date: Fri, 27 Mar 2026 20:46:48 +0900 Subject: [PATCH 28/70] =?UTF-8?q?docs:=20README=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=83=81=ED=83=9C=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6a052d0f6b..9618d8e005 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ### 게임 초기화 -- [ ] 한나라가 위, 초나라를 아래로 위치시켜 보드를 초기화한다. +- [x] 한나라가 위, 초나라를 아래로 위치시켜 보드를 초기화한다. ### 게임 진행 @@ -53,7 +53,7 @@ ## 출력 -- [ ] 보드판을 출력한다. +- [x] 보드판을 출력한다. ```java 게임을 시작하겠습니다. @@ -104,7 +104,11 @@ ### Position -- [x] 장기판 범위를 벗어난 경우 +- [x] 장기판 범위를 벗어난 경우 ```java [ERROR] 장기판 범위를 벗어난 좌표입니다. ``` +- [ ] 기물이 이동할 수 없을 경우 + ``` + [ERROR] 유효하지 않는 행마입니다. + ``` From 83fe29bf92acdef85b3398c41db413b29781be33 Mon Sep 17 00:00:00 2001 From: smiinii Date: Fri, 27 Mar 2026 22:06:52 +0900 Subject: [PATCH 29/70] =?UTF-8?q?feat:=20=EC=B0=A8(Cha)=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=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=8C=90=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movestorage/ChaMoveStorage.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java b/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java index fe79040317..5e4cd2728b 100644 --- a/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java @@ -1,12 +1,70 @@ package janggi.domain.movestorage; import janggi.domain.BoardState; +import janggi.domain.Column; import janggi.domain.Position; +import janggi.domain.Row; + +import java.util.List; public class ChaMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) + // TODO: if문을 어떻게 줄일까? (2026. 3. 27.) @Override public boolean canMove(Position from, Position to, BoardState boardState) { + List fromPosition = from.getPosition(); + List toPosition = to.getPosition(); + + int fromX = fromPosition.getFirst(); + int fromY = fromPosition.getLast(); + + int toX = toPosition.getFirst(); + int toY = toPosition.getLast(); + + if (fromX == toX) { + if (fromY < toY) { + int min = fromY; + int max = toY; + for (int i = min + 1; i < max; i++) { + Position position = Position.of(Row.of(fromX), Column.of(i)); + if (boardState.hasPieceAt(position)) { + return false; + } + } + } + if (fromY > toY) { + int min = toY; + int max = fromY; + for (int i = min + 1; i < max; i++) { + Position position = Position.of(Row.of(fromX), Column.of(i)); + if (boardState.hasPieceAt(position)) { + return false; + } + } + } + } + + if (fromY == toY) { + if (fromX < toX) { + int min = fromX; + int max = toX; + for (int i = min + 1; i < max; i++) { + Position position = Position.of(Row.of(i), Column.of(fromY)); + if (boardState.hasPieceAt(position)) { + return false; + } + } + } + if (fromX > toX) { + int min = toX; + int max = fromX; + for (int i = min + 1; i < max; i++) { + Position position = Position.of(Row.of(i), Column.of(fromY)); + if (boardState.hasPieceAt(position)) { + return false; + } + } + } + } return true; } } From fb2f492fb3640e4bea01a317e7e412d28411b3bf Mon Sep 17 00:00:00 2001 From: smiinii Date: Fri, 27 Mar 2026 22:07:00 +0900 Subject: [PATCH 30/70] =?UTF-8?q?test:=20=EC=B0=A8(Cha)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=9C=84=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 --- .../movestorage/ChaMoveStorageTest.java | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java diff --git a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java new file mode 100644 index 0000000000..efc616f033 --- /dev/null +++ b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java @@ -0,0 +1,138 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; +import janggi.domain.Position; +import janggi.domain.Row; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ChaMoveStorageTest { + private static class fakeBoard implements BoardState { + @Override + public boolean hasPieceAt(Position position) { + return false; + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + private static class ObstaclFakeBoard implements BoardState { + private final List obstacles; + + public ObstaclFakeBoard(List obstacles) { + this.obstacles = new ArrayList<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.contains(position); + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높다() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + BoardState boardState = new fakeBoard(); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮다() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + BoardState boardState = new fakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높다() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + BoardState boardState = new fakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮다() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + BoardState boardState = new fakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높으면서_방해물이_있으면_예외처리() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + Position obstacl = Position.of(Row.of(0), Column.of(2)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstacl)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮으면서_방해물이_있으면_예외처리() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + Position obstacl = Position.of(Row.of(0), Column.of(1)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstacl)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높으면서_방해물이_있으면_예외처리() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + Position obstacl = Position.of(Row.of(2), Column.of(0)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstacl)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮으면서_방해물이_있으면_예외처리() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + Position obstacl = Position.of(Row.of(1), Column.of(0)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstacl)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } +} From de02ec9b5d0231f9b0fcd05fb3b6be013f8cb17e Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 10:35:14 +0900 Subject: [PATCH 31/70] =?UTF-8?q?refactor:=20=EC=B0=A8(Cha)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movestorage/ChaMoveStorage.java | 59 +++++++------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java b/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java index 5e4cd2728b..584565738f 100644 --- a/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/ChaMoveStorage.java @@ -7,8 +7,8 @@ import java.util.List; -public class ChaMoveStorage implements MoveStorage{ - // TODO: if문을 어떻게 줄일까? (2026. 3. 27.) +public class ChaMoveStorage implements MoveStorage { + @Override public boolean canMove(Position from, Position to, BoardState boardState) { List fromPosition = from.getPosition(); @@ -16,52 +16,33 @@ public boolean canMove(Position from, Position to, BoardState boardState) { int fromX = fromPosition.getFirst(); int fromY = fromPosition.getLast(); - int toX = toPosition.getFirst(); int toY = toPosition.getLast(); + if (fromX != toX && fromY != toY) { + return false; + } + if (fromX == toX) { - if (fromY < toY) { - int min = fromY; - int max = toY; - for (int i = min + 1; i < max; i++) { - Position position = Position.of(Row.of(fromX), Column.of(i)); - if (boardState.hasPieceAt(position)) { - return false; - } - } - } - if (fromY > toY) { - int min = toY; - int max = fromY; - for (int i = min + 1; i < max; i++) { - Position position = Position.of(Row.of(fromX), Column.of(i)); - if (boardState.hasPieceAt(position)) { - return false; - } + int start = Math.min(fromY, toY) + 1; + int end = Math.max(fromY, toY); + + for (int i = start; i < end; i++) { + Position position = Position.of(Row.of(fromX), Column.of(i)); + if (boardState.hasPieceAt(position)) { + return false; } } } if (fromY == toY) { - if (fromX < toX) { - int min = fromX; - int max = toX; - for (int i = min + 1; i < max; i++) { - Position position = Position.of(Row.of(i), Column.of(fromY)); - if (boardState.hasPieceAt(position)) { - return false; - } - } - } - if (fromX > toX) { - int min = toX; - int max = fromX; - for (int i = min + 1; i < max; i++) { - Position position = Position.of(Row.of(i), Column.of(fromY)); - if (boardState.hasPieceAt(position)) { - return false; - } + int start = Math.min(fromX, toX) + 1; + int end = Math.max(fromX, toX); + + for (int i = start; i < end; i++) { + Position position = Position.of(Row.of(i), Column.of(fromY)); + if (boardState.hasPieceAt(position)) { + return false; } } } From ec53683147379ab8fcd3c1b7b8bc69c904d0a497 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 10:35:22 +0900 Subject: [PATCH 32/70] =?UTF-8?q?test:=20ChaMoveStorage=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=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 --- .../movestorage/ChaMoveStorageTest.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java index efc616f033..49ebced299 100644 --- a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java @@ -13,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; class ChaMoveStorageTest { - private static class fakeBoard implements BoardState { + private static class FakeBoard implements BoardState { @Override public boolean hasPieceAt(Position position) { return false; @@ -44,52 +44,52 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_멱이_없다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); Position to = Position.of(Row.of(0), Column.of(3)); - BoardState boardState = new fakeBoard(); + BoardState boardState = new FakeBoard(); // when & then assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_멱이_없다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(3)); Position to = Position.of(Row.of(0), Column.of(0)); - BoardState boardState = new fakeBoard(); + BoardState boardState = new FakeBoard(); // when & then assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_멱이_없다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); Position to = Position.of(Row.of(3), Column.of(0)); - BoardState boardState = new fakeBoard(); + BoardState boardState = new FakeBoard(); // when & then assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_멱이_없다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(3), Column.of(0)); Position to = Position.of(Row.of(0), Column.of(0)); - BoardState boardState = new fakeBoard(); + BoardState boardState = new FakeBoard(); // when & then assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높으면서_방해물이_있으면_예외처리() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높으면서_멱이_있으면_예외처리() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); @@ -101,7 +101,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮으면서_방해물이_있으면_예외처리() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮으면서_멱이_있으면_예외처리() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(3)); @@ -113,7 +113,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높으면서_방해물이_있으면_예외처리() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높으면서_멱이_있으면_예외처리() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); @@ -125,7 +125,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮으면서_방해물이_있으면_예외처리() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮으면서_멱이_있으면_예외처리() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(3), Column.of(0)); From 0e1ec00d5cdea1c121d1e56188767232f03a000e Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 10:59:22 +0900 Subject: [PATCH 33/70] =?UTF-8?q?test:=20=EC=B0=A8(Cha)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=B6=88=EA=B0=80=EB=8A=A5=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=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 --- .../janggi/domain/movestorage/ChaMoveStorageTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java index 49ebced299..9d18a67d77 100644 --- a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java @@ -88,6 +88,17 @@ public Piece getPieceAt(Position position) { assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); } + @Test + void 차가_아예_갈_수_없는_행마면_예외처리() { + // given + MoveStorage moveStorage = new ChaMoveStorage(); + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(1), Column.of(3)); + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + @Test void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높으면서_멱이_있으면_예외처리() { // given From 58baa25596a5aad555beb84130c948952a6d8051 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 11:59:28 +0900 Subject: [PATCH 34/70] =?UTF-8?q?feat:=20=ED=8F=AC(Po)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movestorage/PoMoveStorage.java | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/movestorage/PoMoveStorage.java b/src/main/java/janggi/domain/movestorage/PoMoveStorage.java index 53a420590c..dcce09a47e 100644 --- a/src/main/java/janggi/domain/movestorage/PoMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/PoMoveStorage.java @@ -1,12 +1,73 @@ package janggi.domain.movestorage; import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; import janggi.domain.Position; +import janggi.domain.Row; + +import java.util.List; + +public class PoMoveStorage implements MoveStorage { -public class PoMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) @Override public boolean canMove(Position from, Position to, BoardState boardState) { + List fromPosition = from.getPosition(); + List toPosition = to.getPosition(); + + int fromX = fromPosition.getFirst(); + int fromY = fromPosition.getLast(); + int toX = toPosition.getFirst(); + int toY = toPosition.getLast(); + + if (fromX != toX && fromY != toY) { + return false; + } + + int jumpCount = 0; + + if (fromX == toX) { + int start = Math.min(fromY, toY) + 1; + int end = Math.max(fromY, toY); + + for (int i = start; i < end; i++) { + Position position = Position.of(Row.of(fromX), Column.of(i)); + if (boardState.hasPieceAt(position)) { + Piece jumpPiece = boardState.getPieceAt(position); + if (jumpPiece.getName().equals("包")) { + return false; + } + jumpCount++; + } + } + } + + if (fromY == toY) { + int start = Math.min(fromX, toX) + 1; + int end = Math.max(fromX, toX); + + for (int i = start; i < end; i++) { + Position position = Position.of(Row.of(i), Column.of(fromY)); + if (boardState.hasPieceAt(position)) { + Piece jumpPiece = boardState.getPieceAt(position); + if (jumpPiece.getName().equals("包")) { + return false; + } + jumpCount++; + } + } + } + + if (jumpCount != 1) { + return false; + } + + if (boardState.hasPieceAt(to)) { + Piece targetPiece = boardState.getPieceAt(to); + if (targetPiece.getName().equals("包")) { + return false; + } + } return true; } } From c67f4f3e186b6254a3bcf5222efe303ed5f6885e Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 11:59:41 +0900 Subject: [PATCH 35/70] =?UTF-8?q?test:=20=ED=8F=AC(Po)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=9C=84=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/movestorage/PoMoveStorageTest.java | 511 ++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100644 src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java diff --git a/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java new file mode 100644 index 0000000000..fdfa6579c4 --- /dev/null +++ b/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java @@ -0,0 +1,511 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; +import janggi.domain.Position; +import janggi.domain.Row; +import janggi.domain.Team; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class PoMoveStorageTest { + + private static class FakeBoard implements BoardState { + @Override + public boolean hasPieceAt(Position position) { + return false; + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + private static class ObstaclFakeBoard implements BoardState { + private final Map obstacles; + + public ObstaclFakeBoard(Map obstacles) { + this.obstacles = new HashMap<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.containsKey(position); + } + + @Override + public Piece getPieceAt(Position position) { + return obstacles.get(position); + } + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포가_아니다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(1)); + Piece obstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포가_아니다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(1)); + Piece obstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포가_아니다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(2), Column.of(0)); + Piece obstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포가_아니다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(2), Column.of(0)); + Piece obstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 포가_아예_갈_수_없는_행마면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(1), Column.of(3)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(1)); + Piece obstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_기물이_없으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_기물이_없으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_기물이_없으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_기물이_없으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(3)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(0)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(3), Column.of(0)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(0)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(2)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(0), Column.of(2)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(2), Column.of(0)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position obstaclePosition = Position.of(Row.of(2), Column.of(0)); + Piece obstaclePiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + BoardState boardState = new ObstaclFakeBoard(Map.of(obstaclePosition, obstaclePiece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + + Position pathObstaclePosition = Position.of(Row.of(0), Column.of(2)); + Piece pathObstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position targetPosition = Position.of(Row.of(0), Column.of(3)); + Piece targetPiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + Map initialPieces = Map.of( + pathObstaclePosition, pathObstaclePiece, + targetPosition, targetPiece + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position pathObstaclePosition = Position.of(Row.of(0), Column.of(2)); + Piece pathObstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position targetPosition = Position.of(Row.of(0), Column.of(0)); + Piece targetPiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + Map initialPieces = Map.of( + pathObstaclePosition, pathObstaclePiece, + targetPosition, targetPiece + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + + Position pathObstaclePosition = Position.of(Row.of(2), Column.of(0)); + Piece pathObstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position targetPosition = Position.of(Row.of(3), Column.of(0)); + Piece targetPiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + Map initialPieces = Map.of( + pathObstaclePosition, pathObstaclePiece, + targetPosition, targetPiece + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_s낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position pathObstaclePosition = Position.of(Row.of(2), Column.of(0)); + Piece pathObstaclePiece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position targetPosition = Position.of(Row.of(0), Column.of(0)); + Piece targetPiece = new Piece(new PoMoveStorage(), Team.HAN, 7, "包"); + + Map initialPieces = Map.of( + pathObstaclePosition, pathObstaclePiece, + targetPosition, targetPiece + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_기물이_2개_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(3)); + + Position pathObstaclePosition1 = Position.of(Row.of(0), Column.of(1)); + Piece pathObstaclePiece1 = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position pathObstaclePosition2 = Position.of(Row.of(0), Column.of(2)); + Piece pathObstaclePiece2 = new Piece(new MaMoveStorage(), Team.HAN, 5, "馬"); + + Map initialPieces = Map.of( + pathObstaclePosition1, pathObstaclePiece1, + pathObstaclePosition2, pathObstaclePiece2 + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_기물이_2개_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(3)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position pathObstaclePosition1 = Position.of(Row.of(0), Column.of(1)); + Piece pathObstaclePiece1 = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position pathObstaclePosition2 = Position.of(Row.of(0), Column.of(2)); + Piece pathObstaclePiece2 = new Piece(new MaMoveStorage(), Team.HAN, 5, "馬"); + + Map initialPieces = Map.of( + pathObstaclePosition1, pathObstaclePiece1, + pathObstaclePosition2, pathObstaclePiece2 + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_기물이_2개_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(3), Column.of(0)); + + Position pathObstaclePosition1 = Position.of(Row.of(1), Column.of(0)); + Piece pathObstaclePiece1 = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position pathObstaclePosition2 = Position.of(Row.of(2), Column.of(0)); + Piece pathObstaclePiece2 = new Piece(new MaMoveStorage(), Team.HAN, 5, "馬"); + + Map initialPieces = Map.of( + pathObstaclePosition1, pathObstaclePiece1, + pathObstaclePosition2, pathObstaclePiece2 + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_기물이_2개_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new PoMoveStorage(); + + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(0)); + + Position pathObstaclePosition1 = Position.of(Row.of(1), Column.of(0)); + Piece pathObstaclePiece1 = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Position pathObstaclePosition2 = Position.of(Row.of(2), Column.of(0)); + Piece pathObstaclePiece2 = new Piece(new MaMoveStorage(), Team.HAN, 5, "馬"); + + Map initialPieces = Map.of( + pathObstaclePosition1, pathObstaclePiece1, + pathObstaclePosition2, pathObstaclePiece2 + ); + + BoardState boardState = new ObstaclFakeBoard(initialPieces); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } +} From 004fcf50358513dd1c2e98758d0e192bf47aa61b Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 14:20:22 +0900 Subject: [PATCH 36/70] =?UTF-8?q?feat:=20Position=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20equals=EC=99=80=20hashCode=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=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/Position.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 02ec16790a..7d5df30033 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; public class Position { private static final Map CACHE = new HashMap<>(); @@ -39,4 +40,16 @@ public List getPosition() { position.add(y.getColumn()); return position; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Position position = (Position) o; + return Objects.equals(x, position.x) && Objects.equals(y, position.y); + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } } From 562a9ce23b3bb2f5fa6c63ec222818a99c8d6326 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 16:09:10 +0900 Subject: [PATCH 37/70] =?UTF-8?q?feat:=20=EC=83=81(Sang)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movestorage/SangMoveStorage.java | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/movestorage/SangMoveStorage.java b/src/main/java/janggi/domain/movestorage/SangMoveStorage.java index 4ea8ab5264..63454f7f96 100644 --- a/src/main/java/janggi/domain/movestorage/SangMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/SangMoveStorage.java @@ -1,12 +1,71 @@ package janggi.domain.movestorage; import janggi.domain.BoardState; +import janggi.domain.Column; import janggi.domain.Position; +import janggi.domain.Row; + +import java.util.ArrayList; +import java.util.List; public class SangMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) + private static final int FORWARD = 3; + private static final int DIAGONAL = 2; + + private static final int PATH_STEP_2 = 2; + private static final int PATH_STEP_1 = 1; + private static final int PATH_STEP_0 = 0; + @Override public boolean canMove(Position from, Position to, BoardState boardState) { + List fromPosition = from.getPosition(); + List toPosition = to.getPosition(); + + int fromX = fromPosition.getFirst(); + int fromY = fromPosition.getLast(); + int toX = toPosition.getFirst(); + int toY = toPosition.getLast(); + + int diffX = toX - fromX; + int diffY = toY - fromY; + + boolean isSangMove = (Math.abs(diffX) == FORWARD && Math.abs(diffY) == DIAGONAL) || + (Math.abs(diffX) == DIAGONAL && Math.abs(diffY) == FORWARD); + + if (!isSangMove) { + return false; + } + + List movementPathPositions = new ArrayList<>(); + + int signX = Integer.signum(diffX); + int signY = Integer.signum(diffY); + + if (Math.abs(diffX) == FORWARD) { + int step1X = fromX + (signX * PATH_STEP_1); + int step1Y = fromY + (signY * PATH_STEP_0); + movementPathPositions.add(Position.of(Row.of(step1X), Column.of(step1Y))); + + int step2X = fromX + (signX * PATH_STEP_2); + int step2Y = fromY + (signY * PATH_STEP_1); + movementPathPositions.add(Position.of(Row.of(step2X), Column.of(step2Y))); + } + + if (Math.abs(diffY) == FORWARD) { + int step1X = fromX + (signX * PATH_STEP_0); + int step1Y = fromY + (signY * PATH_STEP_1); + movementPathPositions.add(Position.of(Row.of(step1X), Column.of(step1Y))); + + int step2X = fromX + (signX * PATH_STEP_1); + int step2Y = fromY + (signY * PATH_STEP_2); + movementPathPositions.add(Position.of(Row.of(step2X), Column.of(step2Y))); + } + + for (Position position : movementPathPositions) { + if (boardState.hasPieceAt(position)) { + return false; + } + } return true; } } From 39522081420ea0fb6287d8155d4f95972d02d9ad Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 16:09:53 +0900 Subject: [PATCH 38/70] =?UTF-8?q?test:=20=EC=83=81(Sang)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=9C=84=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 --- .../movestorage/SangMoveStorageTest.java | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java diff --git a/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java new file mode 100644 index 0000000000..929cec3dcb --- /dev/null +++ b/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java @@ -0,0 +1,170 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; +import janggi.domain.Position; +import janggi.domain.Row; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SangMoveStorageTest { + + private static class FakeBoard implements BoardState { + @Override + public boolean hasPieceAt(Position position) { + return false; + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + private static class ObstaclFakeBoard implements BoardState { + private final List obstacles; + + public ObstaclFakeBoard(List obstacles) { + this.obstacles = new ArrayList<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.contains(position); + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + @Test + void 행마_성공_테스트() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(7), Column.of(2)); + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 상이_갈_수_없는_좌표가_들어오면_예외처리() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(7), Column.of(3)); + BoardState boardState = new FakeBoard(); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_위로_3칸_왼쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(2), Column.of(1)); + + Position obstaclPosition = Position.of(Row.of(3), Column.of(2)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_위로_3칸_오른쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(6), Column.of(1)); + + Position obstaclPosition = Position.of(Row.of(5), Column.of(2)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_오른쪽으로_3칸_위로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(7), Column.of(2)); + + Position obstaclPosition = Position.of(Row.of(6), Column.of(3)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_오른쪽으로_3칸_아래로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(7), Column.of(6)); + + Position obstaclPosition = Position.of(Row.of(6), Column.of(5)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_아래로_3칸_오른쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(6), Column.of(7)); + + Position obstaclPosition = Position.of(Row.of(5), Column.of(6)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_아래로_3칸_왼쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(2), Column.of(7)); + + Position obstaclPosition = Position.of(Row.of(3), Column.of(6)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_왼쪽으로_3칸_아래로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(1), Column.of(6)); + + Position obstaclPosition = Position.of(Row.of(2), Column.of(5)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 상이_왼쪽으로_3칸_위로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + MoveStorage moveStorage = new SangMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(1), Column.of(2)); + + Position obstaclPosition = Position.of(Row.of(2), Column.of(3)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } +} From 71ec0046e8c2214459b99d3a195c4bf0d5b62732 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 16:57:18 +0900 Subject: [PATCH 39/70] =?UTF-8?q?feat:=20=EB=A7=88(Ma)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movestorage/MaMoveStorage.java | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/movestorage/MaMoveStorage.java b/src/main/java/janggi/domain/movestorage/MaMoveStorage.java index ae53a3a2b7..2a13da00cb 100644 --- a/src/main/java/janggi/domain/movestorage/MaMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/MaMoveStorage.java @@ -1,12 +1,62 @@ package janggi.domain.movestorage; import janggi.domain.BoardState; +import janggi.domain.Column; import janggi.domain.Position; +import janggi.domain.Row; + +import java.util.ArrayList; +import java.util.List; public class MaMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) + private static final int FORWARD = 2; + private static final int DIAGONAL = 1; + + private static final int PATH_STEP_1 = 1; + private static final int PATH_STEP_0 = 0; + @Override public boolean canMove(Position from, Position to, BoardState boardState) { + List fromPosition = from.getPosition(); + List toPosition = to.getPosition(); + + int fromX = fromPosition.getFirst(); + int fromY = fromPosition.getLast(); + int toX = toPosition.getFirst(); + int toY = toPosition.getLast(); + + int diffX = toX - fromX; + int diffY = toY - fromY; + + boolean isMaMove = (Math.abs(diffX) == FORWARD && Math.abs(diffY) == DIAGONAL) || + (Math.abs(diffX) == DIAGONAL && Math.abs(diffY) == FORWARD); + + if (!isMaMove) { + return false; + } + + List movementPathPositions = new ArrayList<>(); + + int signX = Integer.signum(diffX); + int signY = Integer.signum(diffY); + + if (Math.abs(diffX) == FORWARD) { + int step1X = fromX + (signX * PATH_STEP_1); + int step1Y = fromY + (signY * PATH_STEP_0); + movementPathPositions.add(Position.of(Row.of(step1X), Column.of(step1Y))); + } + + if (Math.abs(diffY) == FORWARD) { + int step1X = fromX + (signX * PATH_STEP_0); + int step1Y = fromY + (signY * PATH_STEP_1); + movementPathPositions.add(Position.of(Row.of(step1X), Column.of(step1Y))); + } + + for (Position position : movementPathPositions) { + if (boardState.hasPieceAt(position)) { + return false; + } + } return true; } } From 7675b639eba95418a23c17f29fc14b1fb016dee5 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 16:57:24 +0900 Subject: [PATCH 40/70] =?UTF-8?q?test:=20=EB=A7=88(Ma)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=9C=84=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/movestorage/MaMoveStorageTest.java | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java diff --git a/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java new file mode 100644 index 0000000000..2ad5049461 --- /dev/null +++ b/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java @@ -0,0 +1,169 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; +import janggi.domain.Position; +import janggi.domain.Row; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class MaMoveStorageTest { + private static class FakeBoard implements BoardState { + @Override + public boolean hasPieceAt(Position position) { + return false; + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + private static class ObstaclFakeBoard implements BoardState { + private final List obstacles; + + public ObstaclFakeBoard(List obstacles) { + this.obstacles = new ArrayList<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.contains(position); + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + @Test + void 행마_성공_테스트() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(6), Column.of(3)); + BoardState boardState = new FakeBoard(); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 마가_갈_수_없는_좌표가_들어오면_예외처리() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(6), Column.of(4)); + BoardState boardState = new FakeBoard(); + + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_위로_2칸_왼쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(3), Column.of(2)); + + Position obstaclPosition = Position.of(Row.of(4), Column.of(3)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_위로_2칸_오른쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(5), Column.of(2)); + + Position obstaclPosition = Position.of(Row.of(4), Column.of(3)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_오른쪽으로_2칸_위로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(6), Column.of(3)); + + Position obstaclPosition = Position.of(Row.of(5), Column.of(4)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_오른쪽으로_2칸_아래로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(6), Column.of(5)); + + Position obstaclPosition = Position.of(Row.of(5), Column.of(4)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_아래로_2칸_오른쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(5), Column.of(6)); + + Position obstaclPosition = Position.of(Row.of(4), Column.of(5)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_아래로_2칸_왼쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + // given + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(3), Column.of(6)); + + Position obstaclPosition = Position.of(Row.of(4), Column.of(5)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_왼쪽으로_2칸_아래로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(2), Column.of(5)); + + Position obstaclPosition = Position.of(Row.of(3), Column.of(4)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 마가_왼쪽으로_2칸_위로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + MoveStorage moveStorage = new MaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(4)); + Position to = Position.of(Row.of(2), Column.of(3)); + + Position obstaclPosition = Position.of(Row.of(3), Column.of(4)); + BoardState boardState = new ObstaclFakeBoard(List.of(obstaclPosition)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } +} From b15a267cafc6a3a9051b9f657db6d2be2c587c0f Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 18:12:44 +0900 Subject: [PATCH 41/70] =?UTF-8?q?feat:=20=EC=A1=B8(Jol)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EC=A0=80=EC=9E=A5=EC=86=8C=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B8=B0=EB=B3=B8=20=EA=B5=AC=EC=A1=B0=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/movestorage/JolMoveStorage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java index 7c07bb7220..968f2dd4ac 100644 --- a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java @@ -2,6 +2,9 @@ import janggi.domain.BoardState; import janggi.domain.Position; +import janggi.domain.Team; + +import java.util.List; public class JolMoveStorage implements MoveStorage{ // TODO: 이동 규칙 구현 (2026. 3. 26.) From d08cb7f2eac92845b15bea45ae327178017d4ec0 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 18:12:52 +0900 Subject: [PATCH 42/70] =?UTF-8?q?test:=20=EC=A1=B8(Jol)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=9C=84=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 --- .../movestorage/JolMoveStorageTest.java | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java diff --git a/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java new file mode 100644 index 0000000000..862c48ab66 --- /dev/null +++ b/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java @@ -0,0 +1,130 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; +import janggi.domain.Position; +import janggi.domain.Row; +import janggi.domain.Team; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class JolMoveStorageTest { + private static class FakeBoard implements BoardState { + @Override + public boolean hasPieceAt(Position position) { + return false; + } + + @Override + public Piece getPieceAt(Position position) { + return null; + } + } + + private static class JolFakeBoard implements BoardState { + private final Map obstacles; + + public JolFakeBoard(Map obstacles) { + this.obstacles = new HashMap<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.containsKey(position); + } + + @Override + public Piece getPieceAt(Position position) { + return obstacles.get(position); + } + } + + @Test + void 초나라_졸은_위로_한_칸_전진할_수_있다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(6)); + Position to = Position.of(Row.of(4), Column.of(5)); + Piece piece = new Piece(new JolMoveStorage(), Team.CHO, 2, "卒"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 초나라_졸은_아래로_한_칸_후퇴할_수_없다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(6)); + Position to = Position.of(Row.of(4), Column.of(7)); + Piece piece = new Piece(new JolMoveStorage(), Team.CHO, 2, "卒"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_졸은_아래로_한_칸_전진할_수_있다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(4), Column.of(4)); + Piece piece = new Piece(new JolMoveStorage(), Team.HAN, 2, "兵"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 한나라_졸은_위로_한_칸_후퇴할_수_없다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(4), Column.of(2)); + Piece piece = new Piece(new JolMoveStorage(), Team.HAN, 2, "兵"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 졸은_왼쪽으로_이동할_수_있다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(3), Column.of(3)); + Piece piece = new Piece(new JolMoveStorage(), Team.CHO, 2, "卒"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 졸은_오른쪽으로_이동할_수_있다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(5), Column.of(3)); + Piece piece = new Piece(new JolMoveStorage(), Team.CHO, 2, "卒"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 이동할_수_없는_행마면_예외처리한다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(5), Column.of(5)); + Piece piece = new Piece(new JolMoveStorage(), Team.CHO, 2, "卒"); + BoardState boardState = new JolFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } +} From 13ed308979deef1ae011b9a270b6b298212215f6 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 18:13:04 +0900 Subject: [PATCH 43/70] =?UTF-8?q?refactor:=20=EA=B6=81(Gung)=EA=B3=BC=20?= =?UTF-8?q?=EC=82=AC(Sa)=20=EC=9D=B4=EB=8F=99=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EC=86=8C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ungMoveStorage.java => GungAndSaMoveStorage.java} | 2 +- .../janggi/domain/movestorage/SaMoveStorage.java | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) rename src/main/java/janggi/domain/movestorage/{GungMoveStorage.java => GungAndSaMoveStorage.java} (82%) delete mode 100644 src/main/java/janggi/domain/movestorage/SaMoveStorage.java diff --git a/src/main/java/janggi/domain/movestorage/GungMoveStorage.java b/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java similarity index 82% rename from src/main/java/janggi/domain/movestorage/GungMoveStorage.java rename to src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java index 0aabe4c6fd..a343822c20 100644 --- a/src/main/java/janggi/domain/movestorage/GungMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java @@ -3,7 +3,7 @@ import janggi.domain.BoardState; import janggi.domain.Position; -public class GungMoveStorage implements MoveStorage{ +public class GungAndSaMoveStorage implements MoveStorage{ // TODO: 이동 규칙 구현 (2026. 3. 26.) @Override public boolean canMove(Position from, Position to, BoardState boardState) { diff --git a/src/main/java/janggi/domain/movestorage/SaMoveStorage.java b/src/main/java/janggi/domain/movestorage/SaMoveStorage.java deleted file mode 100644 index e6031dcb82..0000000000 --- a/src/main/java/janggi/domain/movestorage/SaMoveStorage.java +++ /dev/null @@ -1,12 +0,0 @@ -package janggi.domain.movestorage; - -import janggi.domain.BoardState; -import janggi.domain.Position; - -public class SaMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) - @Override - public boolean canMove(Position from, Position to, BoardState boardState) { - return true; - } -} From 6f30824100dbf53884ab133dd0a087f48408895f Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 18:13:13 +0900 Subject: [PATCH 44/70] =?UTF-8?q?refactor:=20=EA=B6=81(Gung)=EA=B3=BC=20?= =?UTF-8?q?=EC=82=AC(Sa)=20=EC=9D=B4=EB=8F=99=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=86=8C=20=ED=86=B5=ED=95=A9=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardFactory.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/janggi/domain/BoardFactory.java b/src/main/java/janggi/domain/BoardFactory.java index 0db5569594..39a458720c 100644 --- a/src/main/java/janggi/domain/BoardFactory.java +++ b/src/main/java/janggi/domain/BoardFactory.java @@ -1,10 +1,9 @@ package janggi.domain; import janggi.domain.movestorage.ChaMoveStorage; -import janggi.domain.movestorage.GungMoveStorage; +import janggi.domain.movestorage.GungAndSaMoveStorage; import janggi.domain.movestorage.JolMoveStorage; import janggi.domain.movestorage.MaMoveStorage; -import janggi.domain.movestorage.SaMoveStorage; import janggi.domain.movestorage.SangMoveStorage; import java.util.HashMap; @@ -38,12 +37,12 @@ private static void SetHanPieces(Map board) { new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); // 사 board.put(Position.of(Row.of(3), Column.of(0)), - new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + new Piece(new GungAndSaMoveStorage(), Team.HAN, 3, "士")); board.put(Position.of(Row.of(5), Column.of(0)), - new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + new Piece(new GungAndSaMoveStorage(), Team.HAN, 3, "士")); // 궁 board.put(Position.of(Row.of(4), Column.of(1)), - new Piece(new GungMoveStorage(), Team.HAN, 0, "漢")); + new Piece(new GungAndSaMoveStorage(), Team.HAN, 0, "漢")); // 포 board.put(Position.of(Row.of(1), Column.of(2)), new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); @@ -80,12 +79,12 @@ private static void SetChoPieces(Map board) { new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); // 사 board.put(Position.of(Row.of(3), Column.of(9)), - new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + new Piece(new GungAndSaMoveStorage(), Team.HAN, 3, "士")); board.put(Position.of(Row.of(5), Column.of(9)), - new Piece(new SaMoveStorage(), Team.HAN, 3, "士")); + new Piece(new GungAndSaMoveStorage(), Team.HAN, 3, "士")); // 궁 board.put(Position.of(Row.of(4), Column.of(8)), - new Piece(new GungMoveStorage(), Team.HAN, 0, "楚")); + new Piece(new GungAndSaMoveStorage(), Team.HAN, 0, "楚")); // 포 board.put(Position.of(Row.of(1), Column.of(7)), new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); From ac7c8b40f23f9de42254497003775b3b6834d497 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 18:14:30 +0900 Subject: [PATCH 45/70] =?UTF-8?q?test:=20Position=20=EC=A2=8C=ED=91=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=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 --- src/test/java/janggi/domain/PositionTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/java/janggi/domain/PositionTest.java b/src/test/java/janggi/domain/PositionTest.java index de9643389b..bf56f7a987 100644 --- a/src/test/java/janggi/domain/PositionTest.java +++ b/src/test/java/janggi/domain/PositionTest.java @@ -10,9 +10,8 @@ class PositionTest { @Test void 장기판에_모든_좌표가_생성된다() { // when & then - for (int x = 1; x <= 9; x++) { - for(int y = 1; y <= 10; y++) { - + for (int x = 0; x < 9; x++) { + for(int y = 0; y < 10; y++) { Position position1 = Position.of(Row.of(x), Column.of(y)); Position position2 = Position.of(Row.of(x), Column.of(y)); From aca2d4299c3df7e671d1060e45213867f747f320 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 18:15:51 +0900 Subject: [PATCH 46/70] =?UTF-8?q?feat:=20=EC=A1=B8(Jol)=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/movestorage/JolMoveStorage.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java index 968f2dd4ac..0299787b13 100644 --- a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java @@ -7,9 +7,36 @@ import java.util.List; public class JolMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) + private static final int HAN_FORWARD = 1; + private static final int CHO_FORWARD = -1; + public static final int NEXT_TO = 1; + @Override public boolean canMove(Position from, Position to, BoardState boardState) { - return true; + List fromPosition = from.getPosition(); + List toPosition = to.getPosition(); + + int fromX = fromPosition.getFirst(); + int fromY = fromPosition.getLast(); + int toX = toPosition.getFirst(); + int toY = toPosition.getLast(); + + if (Math.abs(fromX - toX) == NEXT_TO && fromY == toY) { + return true; + } + + if (boardState.getPieceAt(from).getTeam() == Team.HAN) { + if (toY - fromY == HAN_FORWARD && fromX == toX) { + return true; + } + } + + if (boardState.getPieceAt(from).getTeam() == Team.CHO) { + if (toY - fromY == CHO_FORWARD && fromX == toX) { + return true; + } + } + + return false; } } From 633b898c5cadbdecded21c1d523ca6d180ea6522 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:16:17 +0900 Subject: [PATCH 47/70] =?UTF-8?q?feat:=20=EA=B6=81(Gung)=EA=B3=BC=20?= =?UTF-8?q?=EC=82=AC(Sa)=20=EC=9D=B4=EB=8F=99=20=EA=B0=80=EB=8A=A5=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=8C=90=EB=8B=A8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movestorage/GungAndSaMoveStorage.java | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java b/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java index a343822c20..b962ea950d 100644 --- a/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java @@ -2,11 +2,49 @@ import janggi.domain.BoardState; import janggi.domain.Position; +import janggi.domain.Team; + +import java.util.List; public class GungAndSaMoveStorage implements MoveStorage{ - // TODO: 이동 규칙 구현 (2026. 3. 26.) @Override public boolean canMove(Position from, Position to, BoardState boardState) { + List fromPosition = from.getPosition(); + List toPosition = to.getPosition(); + + int fromX = fromPosition.getFirst(); + int fromY = fromPosition.getLast(); + int toX = toPosition.getFirst(); + int toY = toPosition.getLast(); + + if (!(3 <= fromX && fromX <= 5) || !(3 <= toX && toX <= 5)) { + return false; + } + + if (boardState.getPieceAt(from).getTeam() == Team.HAN) { + if (!(0 <= fromY && fromY <= 2) || !(0 <= toY && toY <= 2)) { + return false; + } + } + + if (boardState.getPieceAt(from).getTeam() == Team.CHO) { + if (!(7 <= fromY && fromY <= 9) || !(7 <= toY && toY <= 9)) { + return false; + } + } + + if (fromX != toX && fromY != toY) { + return false; + } + + if (fromY == toY && Math.abs(fromX - toX) != 1) { + return false; + } + + if (fromX == toX && Math.abs(fromY - toY) != 1) { + return false; + } + return true; } } From f3cca02f800993f70736f00fe135ef5f9ec92210 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:16:57 +0900 Subject: [PATCH 48/70] =?UTF-8?q?test:=20=EA=B6=81(Gung)=EA=B3=BC=20?= =?UTF-8?q?=EC=82=AC(Sa)=20=EC=9D=B4=EB=8F=99=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=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 --- .../movestorage/GungAndSaMoveStorageTest.java | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 src/test/java/janggi/domain/movestorage/GungAndSaMoveStorageTest.java diff --git a/src/test/java/janggi/domain/movestorage/GungAndSaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/GungAndSaMoveStorageTest.java new file mode 100644 index 0000000000..a946c0704c --- /dev/null +++ b/src/test/java/janggi/domain/movestorage/GungAndSaMoveStorageTest.java @@ -0,0 +1,250 @@ +package janggi.domain.movestorage; + +import janggi.domain.BoardState; +import janggi.domain.Column; +import janggi.domain.Piece; +import janggi.domain.Position; +import janggi.domain.Row; +import janggi.domain.Team; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class GungAndSaMoveStorageTest { + private static class ObstaclFakeBoard implements BoardState { + private final Map obstacles; + + public ObstaclFakeBoard(Map obstacles) { + this.obstacles = new HashMap<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.containsKey(position); + } + + @Override + public Piece getPieceAt(Position position) { + return obstacles.get(position); + } + } + + @Test + void 초나라_왕과_사는_궁성_내부에서_위로_한_칸_이동할_수_있다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(8)); + Position to = Position.of(Row.of(4), Column.of(7)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 초나라_왕과_사는_궁성_내부에서_아래로_한_칸_이동할_수_있다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(8)); + Position to = Position.of(Row.of(4), Column.of(9)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 초나라_왕과_사는_궁성_내부에서_왼쪽으로_한_칸_이동할_수_있다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(8)); + Position to = Position.of(Row.of(3), Column.of(8)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 초나라_왕과_사는_궁성_내부에서_오른쪽으로_한_칸_이동할_수_있다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(8)); + Position to = Position.of(Row.of(5), Column.of(8)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isTrue(); + } + + @Test + void 초나라_왕과_사는_궁성의_좌측_상단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(7)); + Position to = Position.of(Row.of(2), Column.of(7)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 초나라_왕과_사는_궁성의_좌측_중단에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(8)); + Position to = Position.of(Row.of(2), Column.of(8)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 초나라_왕과_사는_궁성의_좌측_하단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(9)); + Position to = Position.of(Row.of(2), Column.of(9)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 초나라_왕과_사는_궁성의_우측_상단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(5), Column.of(7)); + Position to = Position.of(Row.of(6), Column.of(7)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 초나라_왕과_사는_궁성의_우측_중단에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(5), Column.of(8)); + Position to = Position.of(Row.of(6), Column.of(8)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 초나라_왕과_사는_궁성의_우측_하단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(5), Column.of(9)); + Position to = Position.of(Row.of(6), Column.of(9)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 초나라_왕과_사는_궁성_제일_앞줄에서_앞으로_한_칸_더_전진하여_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(7)); + Position to = Position.of(Row.of(4), Column.of(6)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.CHO, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성의_좌측_상단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(0)); + Position to = Position.of(Row.of(2), Column.of(0)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성의_좌측_중단에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(1)); + Position to = Position.of(Row.of(2), Column.of(1)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성의_좌측_하단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(3), Column.of(2)); + Position to = Position.of(Row.of(2), Column.of(2)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성의_우측_상단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(5), Column.of(0)); + Position to = Position.of(Row.of(6), Column.of(0)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성의_우측_중단에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(5), Column.of(1)); + Position to = Position.of(Row.of(6), Column.of(1)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성의_우측_하단_끝에서_궁성_밖으로_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(5), Column.of(2)); + Position to = Position.of(Row.of(6), Column.of(2)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } + + @Test + void 한나라_왕과_사는_궁성_제일_앞줄에서_앞으로_한_칸_더_전진하여_이탈하는_경우_실패를_반환한다() { + // given + MoveStorage moveStorage = new GungAndSaMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(2)); + Position to = Position.of(Row.of(4), Column.of(3)); + Piece piece = new Piece(new GungAndSaMoveStorage(), Team.HAN, 9, "士"); + BoardState boardState = new ObstaclFakeBoard(Map.of(from, piece)); + // when & then + assertThat(moveStorage.canMove(from, to, boardState)).isFalse(); + } +} From e910f04b716cfe9d9f14e9a1390d8808cbf4d355 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:17:09 +0900 Subject: [PATCH 49/70] =?UTF-8?q?test:=20=EC=9D=B4=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movestorage/ChaMoveStorageTest.java | 10 ++--- .../movestorage/JolMoveStorageTest.java | 2 +- .../domain/movestorage/MaMoveStorageTest.java | 18 ++++---- .../domain/movestorage/PoMoveStorageTest.java | 42 +++++++++---------- .../movestorage/SangMoveStorageTest.java | 18 ++++---- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java index 9d18a67d77..be75c1103f 100644 --- a/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/ChaMoveStorageTest.java @@ -89,7 +89,7 @@ public Piece getPieceAt(Position position) { } @Test - void 차가_아예_갈_수_없는_행마면_예외처리() { + void 차가_아예_갈_수_없는_행마면_실패를_반환한다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); @@ -100,7 +100,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높으면서_멱이_있으면_예외처리() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높으면서_멱이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); @@ -112,7 +112,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮으면서_멱이_있으면_예외처리() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮으면서_멱이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(3)); @@ -124,7 +124,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높으면서_멱이_있으면_예외처리() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높으면서_멱이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(0), Column.of(0)); @@ -136,7 +136,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮으면서_멱이_있으면_예외처리() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮으면서_멱이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new ChaMoveStorage(); Position from = Position.of(Row.of(3), Column.of(0)); diff --git a/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java index 862c48ab66..d2801ee6db 100644 --- a/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/JolMoveStorageTest.java @@ -117,7 +117,7 @@ public Piece getPieceAt(Position position) { } @Test - void 이동할_수_없는_행마면_예외처리한다() { + void 이동할_수_없는_행마면_실패를_반환한다() { // given MoveStorage moveStorage = new JolMoveStorage(); Position from = Position.of(Row.of(4), Column.of(3)); diff --git a/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java index 2ad5049461..1fae8c852c 100644 --- a/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/MaMoveStorageTest.java @@ -55,7 +55,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_갈_수_없는_좌표가_들어오면_예외처리() { + void 마가_갈_수_없는_좌표가_들어오면_실패를_반환한다() { // given MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -67,7 +67,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_위로_2칸_왼쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_위로_2칸_왼쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); Position to = Position.of(Row.of(3), Column.of(2)); @@ -79,7 +79,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_위로_2칸_오른쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_위로_2칸_오른쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -92,7 +92,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_오른쪽으로_2칸_위로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_오른쪽으로_2칸_위로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -105,7 +105,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_오른쪽으로_2칸_아래로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_오른쪽으로_2칸_아래로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -118,7 +118,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_아래로_2칸_오른쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_아래로_2칸_오른쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -131,7 +131,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_아래로_2칸_왼쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_아래로_2칸_왼쪽으로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -144,7 +144,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_왼쪽으로_2칸_아래로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_왼쪽으로_2칸_아래로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); Position to = Position.of(Row.of(2), Column.of(5)); @@ -156,7 +156,7 @@ public Piece getPieceAt(Position position) { } @Test - void 마가_왼쪽으로_2칸_위로_1칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 마가_왼쪽으로_2칸_위로_1칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { MoveStorage moveStorage = new MaMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); Position to = Position.of(Row.of(2), Column.of(3)); diff --git a/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java index fdfa6579c4..e5edca1792 100644 --- a/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/PoMoveStorageTest.java @@ -114,7 +114,7 @@ public Piece getPieceAt(Position position) { } @Test - void 포가_아예_갈_수_없는_행마면_예외가_발생한다() { + void 포가_아예_갈_수_없는_행마면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -130,7 +130,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_기물이_없으면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_기물이_없으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -143,7 +143,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_기물이_없으면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_기물이_없으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -156,7 +156,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_기물이_없으면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_기물이_없으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -169,7 +169,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_기물이_없으면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_기물이_없으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -182,7 +182,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -198,7 +198,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -214,7 +214,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -230,7 +230,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -246,7 +246,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -262,7 +262,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -278,7 +278,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -294,7 +294,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -310,7 +310,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -335,7 +335,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -360,7 +360,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -385,7 +385,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_s낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_s낮고_중간에_포가_아닌_기물이_한_개_있고_도착지점_기물이_포면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -410,7 +410,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_기물이_2개_있으면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_높고_중간에_기물이_2개_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -435,7 +435,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_기물이_2개_있으면_예외가_발생한다() { + void 출발지점과_도착지점이_X축은_같고_Y축은_도착지점이_더_낮고_중간에_기물이_2개_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -460,7 +460,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_기물이_2개_있으면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_높고_중간에_기물이_2개_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); @@ -485,7 +485,7 @@ public Piece getPieceAt(Position position) { } @Test - void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_기물이_2개_있으면_예외가_발생한다() { + void 출발지점과_도착지점이_Y축은_같고_X축은_도착지점이_더_낮고_중간에_기물이_2개_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new PoMoveStorage(); diff --git a/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java b/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java index 929cec3dcb..bd29fe661c 100644 --- a/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java +++ b/src/test/java/janggi/domain/movestorage/SangMoveStorageTest.java @@ -56,7 +56,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_갈_수_없는_좌표가_들어오면_예외처리() { + void 상이_갈_수_없는_좌표가_들어오면_실패를_반환한다() { // given MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -68,7 +68,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_위로_3칸_왼쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_위로_3칸_왼쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); Position to = Position.of(Row.of(2), Column.of(1)); @@ -80,7 +80,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_위로_3칸_오른쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_위로_3칸_오른쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -93,7 +93,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_오른쪽으로_3칸_위로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_오른쪽으로_3칸_위로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -106,7 +106,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_오른쪽으로_3칸_아래로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_오른쪽으로_3칸_아래로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -119,7 +119,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_아래로_3칸_오른쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_아래로_3칸_오른쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -132,7 +132,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_아래로_3칸_왼쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_아래로_3칸_왼쪽으로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { // given MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); @@ -145,7 +145,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_왼쪽으로_3칸_아래로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_왼쪽으로_3칸_아래로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); Position to = Position.of(Row.of(1), Column.of(6)); @@ -157,7 +157,7 @@ public Piece getPieceAt(Position position) { } @Test - void 상이_왼쪽으로_3칸_위로_2칸_이동하려_할_때_경로에_기물이_있으면_예외가_발생한다() { + void 상이_왼쪽으로_3칸_위로_2칸_이동하려_할_때_경로에_기물이_있으면_실패를_반환한다() { MoveStorage moveStorage = new SangMoveStorage(); Position from = Position.of(Row.of(4), Column.of(4)); Position to = Position.of(Row.of(1), Column.of(2)); From 782a1da3a1b4a2fe55b51e3f5dce3a4ec95b4920 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:49:18 +0900 Subject: [PATCH 50/70] =?UTF-8?q?feat:=20=EC=9D=B4=EB=8F=99=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=EC=97=90=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Piece.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/Piece.java b/src/main/java/janggi/domain/Piece.java index 027988e7fe..9693e76b70 100644 --- a/src/main/java/janggi/domain/Piece.java +++ b/src/main/java/janggi/domain/Piece.java @@ -1,6 +1,7 @@ package janggi.domain; import janggi.domain.movestorage.MoveStorage; +import janggi.exception.InvalidMoveException; public class Piece { private final MoveStorage moveStorage; @@ -14,12 +15,24 @@ public Piece(MoveStorage moveStorage, Team team, int score, String name) { this.score = score; this.name = name; } - // TODO: 이동가능 여부 구현 (2026. 3. 26.) + public void verifyMove(Position from, Position to, BoardState boardState) { + if (!moveStorage.canMove(from, to, boardState)) { + throw new InvalidMoveException(); + } + + Piece pieceTo = boardState.getPieceAt(to); + if (pieceTo != null && getTeam() == pieceTo.getTeam()) { + throw new InvalidMoveException(); + } } public String getName() { return name; } + + public Team getTeam() { + return team; + } } From 173a6ea2bc487c84a44b9674c744ca241909d0f0 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:49:28 +0900 Subject: [PATCH 51/70] =?UTF-8?q?test:=20Piece=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=9D=B4=EB=8F=99=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=8B=A8=EC=9C=84=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/PieceTest.java | 73 ++++++++++++++++++++++ 1 file changed, 73 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..63ca45c852 --- /dev/null +++ b/src/test/java/janggi/domain/PieceTest.java @@ -0,0 +1,73 @@ +package janggi.domain; + +import janggi.domain.movestorage.JolMoveStorage; +import janggi.domain.movestorage.MoveStorage; +import janggi.exception.InvalidMoveException; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class PieceTest { + private static class ObstaclFakeBoard implements BoardState { + private final Map obstacles; + + public ObstaclFakeBoard(Map obstacles) { + this.obstacles = new HashMap<>(obstacles); + } + + @Override + public boolean hasPieceAt(Position position) { + return obstacles.containsKey(position); + } + + @Override + public Piece getPieceAt(Position position) { + return obstacles.get(position); + } + } + + @Test + void 다른_진영의_기물을_잡았을_경우_예외가_발생하지_않는다() { + // given + MoveStorage moveStorage = new JolMoveStorage(); + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(4), Column.of(4)); + + Piece pieceHan = new Piece(new JolMoveStorage(), Team.HAN, 9, "兵"); + Piece pieceCho = new Piece(new JolMoveStorage(), Team.CHO, 9, "卒"); + + Map fakeBoard = new HashMap<>(); + fakeBoard.put(from, pieceHan); + fakeBoard.put(to, pieceCho); + + BoardState boardState = new ObstaclFakeBoard(fakeBoard); + + // when & then + assertThatCode(() -> pieceHan.verifyMove(from, to, boardState)) + .doesNotThrowAnyException(); + } + + @Test + void 같은_진영의_기물을_잡았을_경우_예외가_발생한다() { + // given + Position from = Position.of(Row.of(4), Column.of(3)); + Position to = Position.of(Row.of(4), Column.of(4)); + + Piece pieceHan1 = new Piece(new JolMoveStorage(), Team.HAN, 2, "兵"); + Piece pieceHan2 = new Piece(new JolMoveStorage(), Team.HAN, 2, "兵"); + + Map fakeBoard = new HashMap<>(); + fakeBoard.put(from, pieceHan1); + fakeBoard.put(to, pieceHan2); + + BoardState boardState = new ObstaclFakeBoard(fakeBoard); + + // when & then + assertThatThrownBy(() -> pieceHan1.verifyMove(from, to, boardState)) + .isInstanceOf(InvalidMoveException.class); + } +} From 0d01534fc68e6c40d12b90e3197010537c567ca7 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:49:35 +0900 Subject: [PATCH 52/70] =?UTF-8?q?feat:=20InvalidMoveException=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/exception/InvalidMoveException.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/janggi/exception/InvalidMoveException.java diff --git a/src/main/java/janggi/exception/InvalidMoveException.java b/src/main/java/janggi/exception/InvalidMoveException.java new file mode 100644 index 0000000000..e281901cb4 --- /dev/null +++ b/src/main/java/janggi/exception/InvalidMoveException.java @@ -0,0 +1,7 @@ +package janggi.exception; + +public class InvalidMoveException extends BusinessException { + public InvalidMoveException() { + super("유효하지 않는 행마입니다."); + } +} From 9778e6e2b565ae7e079655e6b8c731e46087fa21 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 20:49:55 +0900 Subject: [PATCH 53/70] =?UTF-8?q?docs:=20README=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=83=81=ED=83=9C=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9618d8e005..b81062f6eb 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ ```java [ERROR] 장기판 범위를 벗어난 좌표입니다. ``` -- [ ] 기물이 이동할 수 없을 경우 +- [x] 기물이 이동할 수 없을 경우 ``` [ERROR] 유효하지 않는 행마입니다. ``` From dd5d85c73defd029a807b1d4b9cbb0dceb4d9d2b Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 21:33:25 +0900 Subject: [PATCH 54/70] =?UTF-8?q?feat:=20Piece=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20equals=20=EB=B0=8F=20hashCode=20=EA=B5=AC=ED=98=84?= =?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 --- src/main/java/janggi/domain/Piece.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/janggi/domain/Piece.java b/src/main/java/janggi/domain/Piece.java index 9693e76b70..1f9c80166e 100644 --- a/src/main/java/janggi/domain/Piece.java +++ b/src/main/java/janggi/domain/Piece.java @@ -3,6 +3,8 @@ import janggi.domain.movestorage.MoveStorage; import janggi.exception.InvalidMoveException; +import java.util.Objects; + public class Piece { private final MoveStorage moveStorage; private final Team team; @@ -35,4 +37,16 @@ public String getName() { public Team getTeam() { return team; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Piece piece = (Piece) o; + return score == piece.score && Objects.equals(moveStorage, piece.moveStorage) && team == piece.team && Objects.equals(name, piece.name); + } + + @Override + public int hashCode() { + return Objects.hash(moveStorage, team, score, name); + } } From 8ce5db46f79761767807039037a478e9962b13df Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 21:36:15 +0900 Subject: [PATCH 55/70] =?UTF-8?q?feat:=20=EB=B9=88=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Board.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/Board.java index c2f77f7218..365373604f 100644 --- a/src/main/java/janggi/domain/Board.java +++ b/src/main/java/janggi/domain/Board.java @@ -1,5 +1,7 @@ package janggi.domain; +import janggi.exception.EmptyPositionException; + import java.util.HashMap; import java.util.Map; @@ -22,6 +24,11 @@ public Piece getPieceAt(Position position) { public void move(Position from, Position to) { Piece movingPiece = board.get(from); + + if (movingPiece == null) { + throw new EmptyPositionException(); + } + movingPiece.verifyMove(from, to, this); board.remove(from); board.put(to, movingPiece); From 33c47f14921b17d8bf88d68f74c3278977b5b3b9 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 21:36:21 +0900 Subject: [PATCH 56/70] =?UTF-8?q?test:=20Board=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=8B=A8=EC=9C=84=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/BoardTest.java | 68 ++++++++++++++++++++++ 1 file changed, 68 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..05c6046826 --- /dev/null +++ b/src/test/java/janggi/domain/BoardTest.java @@ -0,0 +1,68 @@ +package janggi.domain; + +import janggi.domain.movestorage.JolMoveStorage; +import janggi.exception.EmptyPositionException; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class BoardTest { + @Test + void 보드는_특정_위치에_기물이_존재하는지_확인할_수_있다() { + // give + Position position = Position.of(Row.of(0), Column.of(7)); + Piece piece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + Board board = new Board(Map.of(position, piece)); + + // when & then + assertThat(board.hasPieceAt(position)).isTrue(); + } + + @Test + void 보드는_지정된_좌표의_기물_정보를_알려준다() { + // give + Position position = Position.of(Row.of(0), Column.of(7)); + Piece piece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + Board board = new Board(Map.of(position, piece)); + + // when & then + assertThat(board.getPieceAt(position)).isEqualTo(piece); + } + + @Test + void 기물은_허용된_규칙에_따라_새로운_위치로_이동한다() { + // give + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(1)); + + Position position = Position.of(Row.of(0), Column.of(0)); + Piece piece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Board board = new Board(Map.of(position, piece)); + + // when + board.move(from, to); + + // then + assertThat(board.getPieceAt(to)).isEqualTo(piece); + assertThat(board.hasPieceAt(from)).isFalse(); + } + + @Test + void 기물이_존재하지_않는_곳에서는_이동을_시작할_수_없다() { + // give + Position from = Position.of(Row.of(0), Column.of(0)); + Position to = Position.of(Row.of(0), Column.of(1)); + + Position position = Position.of(Row.of(0), Column.of(7)); + Piece piece = new Piece(new JolMoveStorage(), Team.HAN, 2, "卒"); + + Board board = new Board(Map.of(position, piece)); + + // when & then + assertThatThrownBy(() -> board.move(from, to)).isInstanceOf(EmptyPositionException.class); + } +} From 9f547245e9dffcc37eda4fcd7eec698cad838fa6 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 21:36:27 +0900 Subject: [PATCH 57/70] =?UTF-8?q?feat:=20EmptyPositionException=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/exception/EmptyPositionException.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/janggi/exception/EmptyPositionException.java diff --git a/src/main/java/janggi/exception/EmptyPositionException.java b/src/main/java/janggi/exception/EmptyPositionException.java new file mode 100644 index 0000000000..bc8c38bc56 --- /dev/null +++ b/src/main/java/janggi/exception/EmptyPositionException.java @@ -0,0 +1,7 @@ +package janggi.exception; + +public class EmptyPositionException extends BusinessException { + public EmptyPositionException() { + super("출발지에 이동할 기물이 없습니다."); + } +} From 0b1fc34e554dc649b85237999263c5de62f1c6f3 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 21:36:40 +0900 Subject: [PATCH 58/70] =?UTF-8?q?docs:=20README=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=95=AD=EB=AA=A9=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EC=98=A4=EB=A5=98=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EC=84=A4=EB=AA=85=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index b81062f6eb..b00f6924c0 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,17 @@ ```java [ERROR] 장기판 범위를 벗어난 좌표입니다. ``` + +### Piece + - [x] 기물이 이동할 수 없을 경우 ``` [ERROR] 유효하지 않는 행마입니다. ``` + +### Board + +- [x] 출발지에 이동할 기물이 없는 경우 + ``` + [ERROR] 출발지에 이동할 기물이 없습니다. + ``` From 64ecbd9c68cd3562adb9f5ab003ef78a4c45ec95 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:12:12 +0900 Subject: [PATCH 59/70] =?UTF-8?q?fix:=20=EC=B4=88=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EB=B0=B0=EC=B9=98=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardFactory.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/janggi/domain/BoardFactory.java b/src/main/java/janggi/domain/BoardFactory.java index 39a458720c..3da70d700e 100644 --- a/src/main/java/janggi/domain/BoardFactory.java +++ b/src/main/java/janggi/domain/BoardFactory.java @@ -64,42 +64,42 @@ private static void SetHanPieces(Map board) { private static void SetChoPieces(Map board) { // 차 board.put(Position.of(Row.of(0), Column.of(9)), - new Piece(new ChaMoveStorage(), Team.HAN, 13, "車")); + new Piece(new ChaMoveStorage(), Team.CHO, 13, "車")); board.put(Position.of(Row.of(8), Column.of(9)), - new Piece(new ChaMoveStorage(), Team.HAN, 13, "車")); + new Piece(new ChaMoveStorage(), Team.CHO, 13, "車")); // 상 board.put(Position.of(Row.of(1), Column.of(9)), - new Piece(new SangMoveStorage(), Team.HAN, 3, "象")); + new Piece(new SangMoveStorage(), Team.CHO, 3, "象")); board.put(Position.of(Row.of(6), Column.of(9)), - new Piece(new SangMoveStorage(), Team.HAN, 3, "象")); + new Piece(new SangMoveStorage(), Team.CHO, 3, "象")); // 마 board.put(Position.of(Row.of(2), Column.of(9)), - new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); + new Piece(new MaMoveStorage(), Team.CHO, 5, "馬")); board.put(Position.of(Row.of(7), Column.of(9)), - new Piece(new MaMoveStorage(), Team.HAN, 5, "馬")); + new Piece(new MaMoveStorage(), Team.CHO, 5, "馬")); // 사 board.put(Position.of(Row.of(3), Column.of(9)), - new Piece(new GungAndSaMoveStorage(), Team.HAN, 3, "士")); + new Piece(new GungAndSaMoveStorage(), Team.CHO, 3, "士")); board.put(Position.of(Row.of(5), Column.of(9)), - new Piece(new GungAndSaMoveStorage(), Team.HAN, 3, "士")); + new Piece(new GungAndSaMoveStorage(), Team.CHO, 3, "士")); // 궁 board.put(Position.of(Row.of(4), Column.of(8)), - new Piece(new GungAndSaMoveStorage(), Team.HAN, 0, "楚")); + new Piece(new GungAndSaMoveStorage(), Team.CHO, 0, "楚")); // 포 board.put(Position.of(Row.of(1), Column.of(7)), - new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + new Piece(new SangMoveStorage(), Team.CHO, 7, "包")); board.put(Position.of(Row.of(7), Column.of(7)), - new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + new Piece(new SangMoveStorage(), Team.CHO, 7, "包")); // 졸 board.put(Position.of(Row.of(0), Column.of(6)), - new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + new Piece(new JolMoveStorage(), Team.CHO, 2, "卒")); board.put(Position.of(Row.of(2), Column.of(6)), - new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + new Piece(new JolMoveStorage(), Team.CHO, 2, "卒")); board.put(Position.of(Row.of(4), Column.of(6)), - new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + new Piece(new JolMoveStorage(), Team.CHO, 2, "卒")); board.put(Position.of(Row.of(6), Column.of(6)), - new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + new Piece(new JolMoveStorage(), Team.CHO, 2, "卒")); board.put(Position.of(Row.of(8), Column.of(6)), - new Piece(new JolMoveStorage(), Team.HAN, 2, "卒")); + new Piece(new JolMoveStorage(), Team.CHO, 2, "卒")); } } From 55745541cb27dfdf61b23aac134c67d62a09143f Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:12:23 +0900 Subject: [PATCH 60/70] =?UTF-8?q?feat:=20Team=20=EC=97=B4=EA=B1=B0?= =?UTF-8?q?=ED=98=95=EC=97=90=20=ED=8C=80=20=EC=A0=84=ED=99=98=20=EB=B0=8F?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EC=A1=B0=ED=9A=8C=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 --- src/main/java/janggi/domain/Team.java | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/Team.java b/src/main/java/janggi/domain/Team.java index 2a65e39c81..bb288031a2 100644 --- a/src/main/java/janggi/domain/Team.java +++ b/src/main/java/janggi/domain/Team.java @@ -1,6 +1,23 @@ package janggi.domain; public enum Team { - CHO, - HAN; + CHO("초"), + HAN("한"); + + private final String name; + + Team(String name) { + this.name = name; + } + + public Team switchTeam() { + if (this == Team.CHO) { + return Team.HAN; + } + return Team.CHO; + } + + public String getTeam() { + return name; + } } From bec82271f9631c541191b35a7d269e445c279c1e Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:12:35 +0900 Subject: [PATCH 61/70] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=EC=84=B1=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=A4=91=EB=B3=B5=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/movestorage/JolMoveStorage.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java index 0299787b13..fd7ecd09ac 100644 --- a/src/main/java/janggi/domain/movestorage/JolMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/JolMoveStorage.java @@ -25,13 +25,15 @@ public boolean canMove(Position from, Position to, BoardState boardState) { return true; } - if (boardState.getPieceAt(from).getTeam() == Team.HAN) { + Team currentTeam = boardState.getPieceAt(from).getTeam(); + + if (currentTeam == Team.HAN) { if (toY - fromY == HAN_FORWARD && fromX == toX) { return true; } } - if (boardState.getPieceAt(from).getTeam() == Team.CHO) { + if (currentTeam == Team.CHO) { if (toY - fromY == CHO_FORWARD && fromX == toX) { return true; } From c03350e025a6cb0f901d48244280b5f0ae623341 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:12:45 +0900 Subject: [PATCH 62/70] =?UTF-8?q?refactor:=20=ED=8C=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C=EB=A1=9C=20=EC=A4=91=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/movestorage/GungAndSaMoveStorage.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java b/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java index b962ea950d..19bf9891a7 100644 --- a/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/GungAndSaMoveStorage.java @@ -21,13 +21,15 @@ public boolean canMove(Position from, Position to, BoardState boardState) { return false; } - if (boardState.getPieceAt(from).getTeam() == Team.HAN) { + Team currentTeam = boardState.getPieceAt(from).getTeam(); + + if (currentTeam == Team.HAN) { if (!(0 <= fromY && fromY <= 2) || !(0 <= toY && toY <= 2)) { return false; } } - if (boardState.getPieceAt(from).getTeam() == Team.CHO) { + if (currentTeam == Team.CHO) { if (!(7 <= fromY && fromY <= 9) || !(7 <= toY && toY <= 9)) { return false; } From 1e86296ef1a344b164c34b9dda0e4f75b5d3fd70 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:12:53 +0900 Subject: [PATCH 63/70] =?UTF-8?q?feat:=20=ED=94=8C=EB=A0=88=EC=9D=B4=20?= =?UTF-8?q?=ED=84=B4=20=EC=9E=85=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A2=8C=ED=91=9C=20=ED=8C=8C=EC=8B=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 --- src/main/java/janggi/view/InputView.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/janggi/view/InputView.java b/src/main/java/janggi/view/InputView.java index 9c383faac1..3e9968c887 100644 --- a/src/main/java/janggi/view/InputView.java +++ b/src/main/java/janggi/view/InputView.java @@ -1,5 +1,8 @@ package janggi.view; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Scanner; public class InputView { @@ -9,5 +12,23 @@ public InputView() { this.sc = new Scanner(System.in); } + public List playTurn(String team) { + System.out.println(team + "나라 턴입니다."); + List inputFrom = readCoordinates("이동할 기물의 좌표를 입력하세요. (예 : 1, 2)"); + List inputTo = readCoordinates("도착할 좌표를 입력하세요. (예 : 1, 3)"); + + List result = new ArrayList<>(inputFrom); + result.addAll(inputTo); + + return result; + } + + private List readCoordinates(String message) { + System.out.println(message); + return Arrays.stream(sc.nextLine().split(",")) + .map(String::trim) + .map(Integer::parseInt) + .toList(); + } } From ed1ebfd07614f1dfe5ad7b7f41725cf7271a19b8 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:13:01 +0900 Subject: [PATCH 64/70] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=B6=9C=EB=A0=A5=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/view/OutputView.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/janggi/view/OutputView.java b/src/main/java/janggi/view/OutputView.java index 7b68ff4586..b13dca1ce8 100644 --- a/src/main/java/janggi/view/OutputView.java +++ b/src/main/java/janggi/view/OutputView.java @@ -23,6 +23,10 @@ public void printStartMessage() { System.out.println(); } + public void printErrorMessage(String errorMessage) { + System.out.println(errorMessage); + } + public void printBoard(BoardDto boardDto) { String[][] boardView = generateBoardView(boardDto); From 6511015f5b1252fb0ee40b3c56cb7367a4b1caff Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:13:42 +0900 Subject: [PATCH 65/70] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=ED=84=B4=20=EC=A7=84=ED=96=89=20=EB=B0=8F=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/controller/Controller.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/java/janggi/controller/Controller.java b/src/main/java/janggi/controller/Controller.java index 8394ea5c96..b0f88f98ec 100644 --- a/src/main/java/janggi/controller/Controller.java +++ b/src/main/java/janggi/controller/Controller.java @@ -2,10 +2,17 @@ import janggi.domain.Board; import janggi.domain.BoardFactory; +import janggi.domain.Column; +import janggi.domain.Position; +import janggi.domain.Row; +import janggi.domain.Team; import janggi.dto.BoardDto; +import janggi.exception.BusinessException; import janggi.view.InputView; import janggi.view.OutputView; +import java.util.List; + public class Controller { private final InputView inputView; private final OutputView outputView; @@ -19,5 +26,28 @@ public void run() { outputView.printStartMessage(); Board board = new Board(BoardFactory.generate()); outputView.printBoard(BoardDto.from(board)); + + outputView.printStartMessage(); + + Team currentTeam = Team.CHO; + + for (int i = 0; i < 10; i++) { + while (true) { + try { + List positions = inputView.playTurn(currentTeam.getTeam()); + Position from = Position.of(Row.of(positions.get(0)), Column.of(positions.get(1))); + Position to = Position.of(Row.of(positions.get(2)), Column.of(positions.get(3))); + + board.move(from, to); + outputView.printBoard(BoardDto.from(board)); + + currentTeam = currentTeam.switchTeam(); + break; + + } catch (BusinessException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + } } } From 92996353ac7af46089fc954a5f76d31a01024d58 Mon Sep 17 00:00:00 2001 From: smiinii Date: Sat, 28 Mar 2026 23:13:56 +0900 Subject: [PATCH 66/70] =?UTF-8?q?docs:=20README=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A7=84=ED=96=89=20=EC=83=81?= =?UTF-8?q?=ED=99=A9=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b00f6924c0..491ba28db4 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ ### 게임 진행 -- [ ] 초나라 선, 한나라 후로 게임이 반복적으로 진행된다. -- [ ] 입력을 받은 좌표와 기물 규칙에 따라 기물을 이동시킨다. +- [x] 초나라 선, 한나라 후로 게임이 반복적으로 진행된다. +- [x] 입력을 받은 좌표와 기물 규칙에 따라 기물을 이동시킨다. - [ ] 궁을 잡는 수를 두면 장군이다. - [ ] 장군을 피하는 수를 두면 멍군이다. - [ ] 빅장일 때 게임을 종료하기 싫으면 빅장을 깨뜨리는 수를 둘 수 있다. @@ -38,13 +38,13 @@ ## 입력 -- [ ] 초나라가 기물을 선택하고 행마를 입력한다. +- [x] 초나라가 기물을 선택하고 행마를 입력한다. ```java 초나라 턴입니다. 이동할 기물의 좌표와 도착할 좌표를 입력하세요. (예 : (1, 2), (3, 3)) ``` -- [ ] 한나라가 기물을 선택하고 행마를 입력한다. +- [x] 한나라가 기물을 선택하고 행마를 입력한다. ```java 한나라 턴입니다. 이동할 기물의 좌표와 도착할 좌표를 입력하세요. (예 : (1, 2), (3, 3)) @@ -53,21 +53,54 @@ ## 출력 -- [x] 보드판을 출력한다. +- [x] 게임 시작 멘트를 출력한다. ```java 게임을 시작하겠습니다. + ``` + +- [x] 보드판을 출력한다. + + ```java + 0 1 2 3 4 5 6 7 8 - 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 - 丨 一 十 一 十 一 十 一 漢 一 十 一 十 一 十 一 丨 - 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 - 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 - 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 - 丨 一 十 一 十 一 十 一 十 一 十 一 十 一 十 一 丨 - 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 一 十 一 兵 - 丨 一 包 一 十 一 十 一 十 一 十 一 十 一 包 一 丨 - 丨 一 十 一 十 一 十 一 漢 一 十 一 十 一 十 一 丨 - 車 一 象 一 馬 一 士 一 十 一 士 一 象 一 馬 一 車 + 0 [車]-------[馬]-------[象]-------[士]-------[ ]-------[士]-------[象]-------[馬]-------[車] + ㅣ ㅣ ㅣ ㅣ \ ㅣ / ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ \ ㅣ / ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ \ ㅣ / ㅣ ㅣ ㅣ ㅣ + 1 [ ]-------[ ]-------[ ]-------[ ]-------[漢]-------[ ]-------[ ]-------[ ]-------[ ] + ㅣ ㅣ ㅣ ㅣ / ㅣ \ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ / ㅣ \ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ / ㅣ \ ㅣ ㅣ ㅣ ㅣ + 2 [ ]-------[包]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[包]-------[ ] + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + 3 [兵]-------[ ]-------[兵]-------[ ]-------[兵]-------[ ]-------[兵]-------[ ]-------[兵] + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + 4 [ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ] + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + 5 [ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ] + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + 6 [卒]-------[ ]-------[卒]-------[ ]-------[卒]-------[ ]-------[卒]-------[ ]-------[卒] + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ ㅣ + 7 [ ]-------[包]-------[ ]-------[ ]-------[ ]-------[ ]-------[ ]-------[包]-------[ ] + ㅣ ㅣ ㅣ ㅣ \ ㅣ / ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ \ ㅣ / ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ \ ㅣ / ㅣ ㅣ ㅣ ㅣ + 8 [ ]-------[ ]-------[ ]-------[ ]-------[楚]-------[ ]-------[ ]-------[ ]-------[ ] + ㅣ ㅣ ㅣ ㅣ / ㅣ \ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ / ㅣ \ ㅣ ㅣ ㅣ ㅣ + ㅣ ㅣ ㅣ ㅣ / ㅣ \ ㅣ ㅣ ㅣ ㅣ + 9 [車]-------[馬]-------[象]-------[士]-------[ ]-------[士]-------[象]-------[馬]-------[車] ``` - [ ] 장군이면 장군을 출력한다. From ed8c806277c0e9c61f824ae9d8fe2e88cf6bc44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Wed, 1 Apr 2026 15:02:52 +0900 Subject: [PATCH 67/70] =?UTF-8?q?fix:=20=ED=8F=AC=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardFactory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/BoardFactory.java b/src/main/java/janggi/domain/BoardFactory.java index 3da70d700e..46bd558be1 100644 --- a/src/main/java/janggi/domain/BoardFactory.java +++ b/src/main/java/janggi/domain/BoardFactory.java @@ -4,6 +4,7 @@ import janggi.domain.movestorage.GungAndSaMoveStorage; import janggi.domain.movestorage.JolMoveStorage; import janggi.domain.movestorage.MaMoveStorage; +import janggi.domain.movestorage.PoMoveStorage; import janggi.domain.movestorage.SangMoveStorage; import java.util.HashMap; @@ -45,9 +46,9 @@ private static void SetHanPieces(Map board) { new Piece(new GungAndSaMoveStorage(), Team.HAN, 0, "漢")); // 포 board.put(Position.of(Row.of(1), Column.of(2)), - new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + new Piece(new PoMoveStorage(), Team.HAN, 7, "包")); board.put(Position.of(Row.of(7), Column.of(2)), - new Piece(new SangMoveStorage(), Team.HAN, 7, "包")); + new Piece(new PoMoveStorage(), Team.HAN, 7, "包")); // 졸 board.put(Position.of(Row.of(0), Column.of(3)), new Piece(new JolMoveStorage(), Team.HAN, 2, "兵")); From b8018a81fb183c8601a4c9e0d25bdf099330e482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Wed, 1 Apr 2026 15:56:16 +0900 Subject: [PATCH 68/70] =?UTF-8?q?fix:=20=ED=8F=AC=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B7=9C=EC=B9=99=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/BoardFactory.java b/src/main/java/janggi/domain/BoardFactory.java index 46bd558be1..df2dad5f79 100644 --- a/src/main/java/janggi/domain/BoardFactory.java +++ b/src/main/java/janggi/domain/BoardFactory.java @@ -88,9 +88,9 @@ private static void SetChoPieces(Map board) { new Piece(new GungAndSaMoveStorage(), Team.CHO, 0, "楚")); // 포 board.put(Position.of(Row.of(1), Column.of(7)), - new Piece(new SangMoveStorage(), Team.CHO, 7, "包")); + new Piece(new PoMoveStorage(), Team.CHO, 7, "包")); board.put(Position.of(Row.of(7), Column.of(7)), - new Piece(new SangMoveStorage(), Team.CHO, 7, "包")); + new Piece(new PoMoveStorage(), Team.CHO, 7, "包")); // 졸 board.put(Position.of(Row.of(0), Column.of(6)), new Piece(new JolMoveStorage(), Team.CHO, 2, "卒")); From 4d263c4180a2dee7659ce9ed4600d8c31723b407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Wed, 1 Apr 2026 19:49:24 +0900 Subject: [PATCH 69/70] =?UTF-8?q?refactor:=20=20=EA=B0=99=EC=9D=80=20?= =?UTF-8?q?=ED=8C=80=EC=9D=B8=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=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/Piece.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/Piece.java b/src/main/java/janggi/domain/Piece.java index 1f9c80166e..65f1287da3 100644 --- a/src/main/java/janggi/domain/Piece.java +++ b/src/main/java/janggi/domain/Piece.java @@ -25,11 +25,15 @@ public void verifyMove(Position from, Position to, BoardState boardState) { Piece pieceTo = boardState.getPieceAt(to); - if (pieceTo != null && getTeam() == pieceTo.getTeam()) { + if (pieceTo != null && isSameTeam(pieceTo)) { throw new InvalidMoveException(); } } + private boolean isSameTeam(Piece pieceTo) { + return team == pieceTo.getTeam(); + } + public String getName() { return name; } From 86669fe8262eac5165f6404b04a07ba27deacda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B5=AC=EB=AF=BC=EC=84=9C?= Date: Sat, 4 Apr 2026 11:12:23 +0900 Subject: [PATCH 70/70] =?UTF-8?q?chore:=20=EC=A4=91=EA=B0=84=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/BoardState.java | 2 +- src/main/java/janggi/domain/Column.java | 2 +- src/main/java/janggi/domain/Position.java | 4 ++-- src/main/java/janggi/domain/movestorage/MaMoveStorage.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/janggi/domain/BoardState.java b/src/main/java/janggi/domain/BoardState.java index d0894f49b6..ca1eb7fe5f 100644 --- a/src/main/java/janggi/domain/BoardState.java +++ b/src/main/java/janggi/domain/BoardState.java @@ -1,6 +1,6 @@ package janggi.domain; -public interface BoardState { +public interface BoardState { //인터페이스명 (readable) boolean hasPieceAt(Position position); Piece getPieceAt(Position position); } diff --git a/src/main/java/janggi/domain/Column.java b/src/main/java/janggi/domain/Column.java index 68dbf0fc92..57e58543e4 100644 --- a/src/main/java/janggi/domain/Column.java +++ b/src/main/java/janggi/domain/Column.java @@ -9,7 +9,7 @@ public class Column { private static final int MIN = 0; private static final int MAX = 9; - private static final Map CACHE = new HashMap<>(); + private static final Map CACHE = new HashMap<>(); // 직접 실험해서 성능 차이 확인 static { for (int i = MIN; i <= MAX; i++) { diff --git a/src/main/java/janggi/domain/Position.java b/src/main/java/janggi/domain/Position.java index 7d5df30033..017f97613f 100644 --- a/src/main/java/janggi/domain/Position.java +++ b/src/main/java/janggi/domain/Position.java @@ -34,9 +34,9 @@ private static String toKey(Row x, Column y) { return x.getRow() + "," + y.getColumn(); } - public List getPosition() { + public List getPosition() { // Position을 활용 List position = new ArrayList<>(); - position.add(x.getRow()); + position.add(x.getRow()); // 캡슐화 깨짐 position.add(y.getColumn()); return position; } diff --git a/src/main/java/janggi/domain/movestorage/MaMoveStorage.java b/src/main/java/janggi/domain/movestorage/MaMoveStorage.java index 2a13da00cb..fca865b3e0 100644 --- a/src/main/java/janggi/domain/movestorage/MaMoveStorage.java +++ b/src/main/java/janggi/domain/movestorage/MaMoveStorage.java @@ -17,7 +17,7 @@ public class MaMoveStorage implements MoveStorage{ @Override public boolean canMove(Position from, Position to, BoardState boardState) { - List fromPosition = from.getPosition(); + List fromPosition = from.getPosition(); //Row, Col을 사용하지 않고, int를 사용하고 있음 List toPosition = to.getPosition(); int fromX = fromPosition.getFirst();