From 009de5d2ce878e2f001c689f43d2d7ec3c0000e3 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 15:42:57 +0900 Subject: [PATCH 001/110] =?UTF-8?q?refactor(OutputView):=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/status/Team.java | 14 ++------------ .../java/janggi/presentation/ui/OutputView.java | 8 +++++++- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/janggi/domain/status/Team.java b/src/main/java/janggi/domain/status/Team.java index c2f76df039..4b36424af2 100644 --- a/src/main/java/janggi/domain/status/Team.java +++ b/src/main/java/janggi/domain/status/Team.java @@ -1,16 +1,6 @@ package janggi.domain.status; public enum Team { - CHO("초"), - HAN("한"); - - private final String name; - - Team(String name) { - this.name = name; - } - - public String getName() { - return name; - } + CHO, + HAN; } diff --git a/src/main/java/janggi/presentation/ui/OutputView.java b/src/main/java/janggi/presentation/ui/OutputView.java index a42247ac04..579750ac37 100644 --- a/src/main/java/janggi/presentation/ui/OutputView.java +++ b/src/main/java/janggi/presentation/ui/OutputView.java @@ -2,11 +2,17 @@ import janggi.domain.status.Team; import janggi.presentation.dto.GameStatusInfo; +import java.util.Map; public class OutputView { + private static final Map DISPLAY_NAME = Map.of( + Team.HAN, "한", + Team.CHO, "초" + ); + public static void printWinner(Team winner) { - System.out.println("승자는 " + winner.getName()); + System.out.println("승자는 " + DISPLAY_NAME.get(winner)); } public static void printGameStatus(GameStatusInfo status) { From 53df5a92a3c1076f7b03bc9f4bec87d0487fd2ab Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 16:00:09 +0900 Subject: [PATCH 002/110] =?UTF-8?q?chore(Point):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 2 +- src/main/java/janggi/domain/Board.java | 1 + src/main/java/janggi/domain/JanggiGame.java | 1 + src/main/java/janggi/domain/piece/AbstractPiece.java | 2 +- src/main/java/janggi/domain/piece/Cha.java | 2 +- src/main/java/janggi/domain/piece/Jang.java | 2 +- src/main/java/janggi/domain/piece/Jol.java | 2 +- src/main/java/janggi/domain/piece/Ma.java | 2 +- src/main/java/janggi/domain/piece/Pho.java | 2 +- src/main/java/janggi/domain/piece/Piece.java | 2 +- src/main/java/janggi/domain/piece/Sa.java | 2 +- src/main/java/janggi/domain/piece/Sang.java | 2 +- src/main/java/janggi/domain/{ => point}/Point.java | 2 +- src/main/java/janggi/domain/status/ChoTurn.java | 2 +- src/main/java/janggi/domain/status/FinishedGame.java | 2 +- src/main/java/janggi/domain/status/GameStatus.java | 2 +- src/main/java/janggi/domain/status/HanTurn.java | 2 +- src/main/java/janggi/presentation/dto/MoveCommand.java | 2 +- src/main/java/janggi/presentation/dto/PositionInfo.java | 2 +- src/main/java/janggi/util/Parser.java | 2 +- src/test/java/janggi/domain/BoardTest.java | 1 + src/test/java/janggi/domain/PointTest.java | 1 + src/test/java/janggi/domain/piece/ChaTest.java | 2 +- src/test/java/janggi/domain/piece/JangTest.java | 2 +- src/test/java/janggi/domain/piece/JolTest.java | 2 +- src/test/java/janggi/domain/piece/MaTest.java | 2 +- src/test/java/janggi/domain/piece/PhoTest.java | 2 +- src/test/java/janggi/domain/piece/SaTest.java | 2 +- src/test/java/janggi/domain/piece/SangTest.java | 2 +- src/test/java/janggi/domain/status/ChoTurnTest.java | 2 +- src/test/java/janggi/domain/status/HanTurnTest.java | 2 +- 31 files changed, 31 insertions(+), 27 deletions(-) rename src/main/java/janggi/domain/{ => point}/Point.java (98%) diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index fe96f514a1..59cc380d52 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -2,7 +2,7 @@ import janggi.domain.Board; import janggi.domain.JanggiGame; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.piece.Piece; import janggi.presentation.dto.GameStatusInfo; import janggi.presentation.dto.MoveCommand; diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/Board.java index 31b3d4b459..37e0a17cd9 100644 --- a/src/main/java/janggi/domain/Board.java +++ b/src/main/java/janggi/domain/Board.java @@ -2,6 +2,7 @@ import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/main/java/janggi/domain/JanggiGame.java b/src/main/java/janggi/domain/JanggiGame.java index c658f49fa9..d7553ef828 100644 --- a/src/main/java/janggi/domain/JanggiGame.java +++ b/src/main/java/janggi/domain/JanggiGame.java @@ -1,6 +1,7 @@ package janggi.domain; import janggi.domain.piece.Piece; +import janggi.domain.point.Point; import janggi.domain.status.ChoTurn; import janggi.domain.status.GameStatus; import janggi.domain.status.Team; diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java index ccd41feac0..d33c10939f 100644 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -1,6 +1,6 @@ package janggi.domain.piece; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index c801b7feba..76f1b65629 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index 3bcf2a71b8..3cd4729172 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index 6935a6d40d..2889268d52 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index 71b4461f85..089588c656 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index 3ae50de94e..f807357051 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 197ae69c9d..ecbadcf211 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -1,6 +1,6 @@ package janggi.domain.piece; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index 3f1c7ef846..b1cffc3ab7 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index 64bf7eef14..1a9dcc6c82 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -2,7 +2,7 @@ import static java.lang.Math.abs; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; diff --git a/src/main/java/janggi/domain/Point.java b/src/main/java/janggi/domain/point/Point.java similarity index 98% rename from src/main/java/janggi/domain/Point.java rename to src/main/java/janggi/domain/point/Point.java index 56e103b9f7..7d48b42a67 100644 --- a/src/main/java/janggi/domain/Point.java +++ b/src/main/java/janggi/domain/point/Point.java @@ -1,4 +1,4 @@ -package janggi.domain; +package janggi.domain.point; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/janggi/domain/status/ChoTurn.java b/src/main/java/janggi/domain/status/ChoTurn.java index c42515748d..2dbc49c1d1 100644 --- a/src/main/java/janggi/domain/status/ChoTurn.java +++ b/src/main/java/janggi/domain/status/ChoTurn.java @@ -1,7 +1,7 @@ package janggi.domain.status; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; public class ChoTurn implements GameStatus { diff --git a/src/main/java/janggi/domain/status/FinishedGame.java b/src/main/java/janggi/domain/status/FinishedGame.java index 84bbf6390c..b482446a62 100644 --- a/src/main/java/janggi/domain/status/FinishedGame.java +++ b/src/main/java/janggi/domain/status/FinishedGame.java @@ -1,7 +1,7 @@ package janggi.domain.status; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; public class FinishedGame implements GameStatus { diff --git a/src/main/java/janggi/domain/status/GameStatus.java b/src/main/java/janggi/domain/status/GameStatus.java index 1661246ffc..e8337d6e18 100644 --- a/src/main/java/janggi/domain/status/GameStatus.java +++ b/src/main/java/janggi/domain/status/GameStatus.java @@ -1,7 +1,7 @@ package janggi.domain.status; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; public interface GameStatus { Team getTeam(); diff --git a/src/main/java/janggi/domain/status/HanTurn.java b/src/main/java/janggi/domain/status/HanTurn.java index 4d6c4a3be3..56da0ca700 100644 --- a/src/main/java/janggi/domain/status/HanTurn.java +++ b/src/main/java/janggi/domain/status/HanTurn.java @@ -1,7 +1,7 @@ package janggi.domain.status; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; public class HanTurn implements GameStatus { diff --git a/src/main/java/janggi/presentation/dto/MoveCommand.java b/src/main/java/janggi/presentation/dto/MoveCommand.java index f7dcd42497..11539bf09a 100644 --- a/src/main/java/janggi/presentation/dto/MoveCommand.java +++ b/src/main/java/janggi/presentation/dto/MoveCommand.java @@ -1,6 +1,6 @@ package janggi.presentation.dto; -import janggi.domain.Point; +import janggi.domain.point.Point; public record MoveCommand( Point from, diff --git a/src/main/java/janggi/presentation/dto/PositionInfo.java b/src/main/java/janggi/presentation/dto/PositionInfo.java index ec17d28ab7..b9551fcf6b 100644 --- a/src/main/java/janggi/presentation/dto/PositionInfo.java +++ b/src/main/java/janggi/presentation/dto/PositionInfo.java @@ -1,6 +1,6 @@ package janggi.presentation.dto; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceFactory; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/util/Parser.java b/src/main/java/janggi/util/Parser.java index dbd4bc578f..697e3eb9b0 100644 --- a/src/main/java/janggi/util/Parser.java +++ b/src/main/java/janggi/util/Parser.java @@ -1,6 +1,6 @@ package janggi.util; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import janggi.presentation.dto.PositionInfo; import java.util.List; diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 019f52691f..673f913f29 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -6,6 +6,7 @@ import janggi.domain.piece.Pho; import janggi.domain.piece.Piece; import janggi.domain.piece.Sang; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/PointTest.java b/src/test/java/janggi/domain/PointTest.java index 6b66f41872..a1ac8654c4 100644 --- a/src/test/java/janggi/domain/PointTest.java +++ b/src/test/java/janggi/domain/PointTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import janggi.domain.point.Point; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/janggi/domain/piece/ChaTest.java b/src/test/java/janggi/domain/piece/ChaTest.java index c8dd25c4aa..6d010732b5 100644 --- a/src/test/java/janggi/domain/piece/ChaTest.java +++ b/src/test/java/janggi/domain/piece/ChaTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/piece/JangTest.java b/src/test/java/janggi/domain/piece/JangTest.java index c64b25acf3..5f98523115 100644 --- a/src/test/java/janggi/domain/piece/JangTest.java +++ b/src/test/java/janggi/domain/piece/JangTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/janggi/domain/piece/JolTest.java b/src/test/java/janggi/domain/piece/JolTest.java index 9c7e7fd7c9..2f2246be73 100644 --- a/src/test/java/janggi/domain/piece/JolTest.java +++ b/src/test/java/janggi/domain/piece/JolTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/janggi/domain/piece/MaTest.java b/src/test/java/janggi/domain/piece/MaTest.java index bc8b02011c..bd0fb521f4 100644 --- a/src/test/java/janggi/domain/piece/MaTest.java +++ b/src/test/java/janggi/domain/piece/MaTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index 6fd0cded87..1cc55c3e35 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.LinkedHashMap; import java.util.List; diff --git a/src/test/java/janggi/domain/piece/SaTest.java b/src/test/java/janggi/domain/piece/SaTest.java index f00f94c1c2..36d3d7c0c5 100644 --- a/src/test/java/janggi/domain/piece/SaTest.java +++ b/src/test/java/janggi/domain/piece/SaTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/janggi/domain/piece/SangTest.java b/src/test/java/janggi/domain/piece/SangTest.java index fe4c24cc23..9ce6474370 100644 --- a/src/test/java/janggi/domain/piece/SangTest.java +++ b/src/test/java/janggi/domain/piece/SangTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/status/ChoTurnTest.java b/src/test/java/janggi/domain/status/ChoTurnTest.java index 711bbf74e4..d815472225 100644 --- a/src/test/java/janggi/domain/status/ChoTurnTest.java +++ b/src/test/java/janggi/domain/status/ChoTurnTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.piece.Cha; import janggi.domain.piece.Jang; import janggi.domain.piece.Piece; diff --git a/src/test/java/janggi/domain/status/HanTurnTest.java b/src/test/java/janggi/domain/status/HanTurnTest.java index 20c9ff1e97..d54c33f588 100644 --- a/src/test/java/janggi/domain/status/HanTurnTest.java +++ b/src/test/java/janggi/domain/status/HanTurnTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf; import janggi.domain.Board; -import janggi.domain.Point; +import janggi.domain.point.Point; import janggi.domain.piece.Cha; import janggi.domain.piece.Jang; import janggi.domain.piece.Piece; From ce78b3b881c3215858b9ce565fd633bd8d4015fc Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 16:10:15 +0900 Subject: [PATCH 003/110] =?UTF-8?q?refactor(Route):=20Point=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=97=AD=ED=95=A0=EB=B6=80=EC=97=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Board.java | 7 ++++--- .../java/janggi/domain/piece/AbstractPiece.java | 3 ++- src/main/java/janggi/domain/piece/Cha.java | 5 +++-- src/main/java/janggi/domain/piece/Jang.java | 5 +++-- src/main/java/janggi/domain/piece/Jol.java | 5 +++-- src/main/java/janggi/domain/piece/Ma.java | 7 ++++--- src/main/java/janggi/domain/piece/Pho.java | 5 +++-- src/main/java/janggi/domain/piece/Piece.java | 3 ++- src/main/java/janggi/domain/piece/Sa.java | 7 ++++--- src/main/java/janggi/domain/piece/Sang.java | 11 ++++++----- src/main/java/janggi/domain/point/Route.java | 17 +++++++++++++++++ src/test/java/janggi/domain/piece/ChaTest.java | 6 +++--- src/test/java/janggi/domain/piece/JolTest.java | 1 - src/test/java/janggi/domain/piece/MaTest.java | 10 +++++----- src/test/java/janggi/domain/piece/PhoTest.java | 11 ++++++----- src/test/java/janggi/domain/piece/SangTest.java | 6 +++--- 16 files changed, 68 insertions(+), 41 deletions(-) create mode 100644 src/main/java/janggi/domain/point/Route.java diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/Board.java index 37e0a17cd9..6fb3b2f85d 100644 --- a/src/main/java/janggi/domain/Board.java +++ b/src/main/java/janggi/domain/Board.java @@ -3,6 +3,7 @@ import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.LinkedHashMap; import java.util.List; @@ -33,7 +34,7 @@ public void move(Point from, Point to, Team team) { if (targetPiece != null && !piece.canCapture(targetPiece)) { throw new IllegalArgumentException("[ERROR] 이 기물은 해당 타겟을 잡을 수 없습니다."); } - List route = piece.getRoute(from, to); + Route route = piece.getRoute(from, to); if (!piece.canMove(getPieces(route))) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 경로에 장애물이 있거나 규칙에 어긋납니다."); } @@ -56,8 +57,8 @@ public List> getPoints() { ).toList(); } - public List getPieces(List point) { - return point.stream() + public List getPieces(Route point) { + return point.getRoutes().stream() .map(pieces::get) .filter(Objects::nonNull) .toList(); diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java index d33c10939f..712d77fd22 100644 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -1,6 +1,7 @@ package janggi.domain.piece; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -15,7 +16,7 @@ public AbstractPiece(Team team, PieceType type) { } @Override - public abstract List getRoute(Point from, Point to); + public abstract Route getRoute(Point from, Point to); @Override public boolean canCapture(Piece target) { diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index 76f1b65629..da96eae525 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.ArrayList; import java.util.List; @@ -14,7 +15,7 @@ public Cha(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); @@ -34,6 +35,6 @@ public List getRoute(Point from, Point to) { int nextY = from.getRow() + (signY * i); route.add(Point.of(nextX, nextY)); } - return route; + return new Route(route); } } diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index 3cd4729172..d2fe24d67a 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -15,7 +16,7 @@ public Jang(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -24,7 +25,7 @@ public List getRoute(Point from, Point to) { if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return List.of(to); + return new Route(List.of(to)); } @Override diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index 2889268d52..fb59f5bd5e 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -15,7 +16,7 @@ public Jol(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int signY = Integer.compare(pathY, 0); @@ -28,7 +29,7 @@ public List getRoute(Point from, Point to) { if ((super.getTeam().equals(Team.CHO) && signY < 0) || (super.getTeam().equals(Team.HAN) && signY > 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return List.of(to); + return new Route(List.of(to)); } @Override diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index 089588c656..db8cbcd169 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -16,7 +17,7 @@ public Ma(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -27,8 +28,8 @@ public List getRoute(Point from, Point to) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } if (distanceX == LONG_STEP) { - return List.of(Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow())); + return new Route(List.of(Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()))); } - return List.of(Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP))); + return new Route(List.of(Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)))); } } diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index f807357051..4ad7cd516b 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.ArrayList; import java.util.List; @@ -14,7 +15,7 @@ public Pho(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); @@ -34,7 +35,7 @@ public List getRoute(Point from, Point to) { int nextY = from.getRow() + (signY * i); route.add(Point.of(nextX, nextY)); } - return route; + return new Route(route); } @Override diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index ecbadcf211..97ef38d18e 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -1,11 +1,12 @@ package janggi.domain.piece; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; public interface Piece { - List getRoute(Point from, Point to); + Route getRoute(Point from, Point to); PieceType getType(); boolean canMove(List route); boolean isSameTeam(Team team); diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index b1cffc3ab7..1b9f95fcfc 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -15,16 +16,16 @@ public Sa(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); int distanceY = abs(pathY); - if ( distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { + if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return List.of(to); + return new Route(List.of(to)); } @Override diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index 1a9dcc6c82..0633c53f6d 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -16,7 +17,7 @@ public Sang(Team team) { } @Override - public List getRoute(Point from, Point to) { + public Route getRoute(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -29,14 +30,14 @@ public List getRoute(Point from, Point to) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } if (distanceX == LONG_STEP) { - return List.of( + return new Route(List.of( Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()), Point.of(from.getColumn() + signX * SHORT_STEP, from.getRow() + signY) - ); + )); } - return List.of( + return new Route(List.of( Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)), Point.of(from.getColumn() + signX, from.getRow() + signY * SHORT_STEP) - ); + )); } } diff --git a/src/main/java/janggi/domain/point/Route.java b/src/main/java/janggi/domain/point/Route.java new file mode 100644 index 0000000000..8fbc4a5022 --- /dev/null +++ b/src/main/java/janggi/domain/point/Route.java @@ -0,0 +1,17 @@ +package janggi.domain.point; + +import java.util.Collections; +import java.util.List; + +public class Route { + + private final List points; + + public Route(List points) { + this.points = points; + } + + public List getRoutes() { + return Collections.unmodifiableList(points); + } +} diff --git a/src/test/java/janggi/domain/piece/ChaTest.java b/src/test/java/janggi/domain/piece/ChaTest.java index 6d010732b5..177e9ec41e 100644 --- a/src/test/java/janggi/domain/piece/ChaTest.java +++ b/src/test/java/janggi/domain/piece/ChaTest.java @@ -4,8 +4,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -23,10 +23,10 @@ void straight_back_route(int x, int y, int result) { Point to = Point.of(x, y); // when - List route = cha.getRoute(from, to); + Route route = cha.getRoute(from, to); // then - assertThat(route.size()).isEqualTo(result); + assertThat(route.getRoutes().size()).isEqualTo(result); } @Test diff --git a/src/test/java/janggi/domain/piece/JolTest.java b/src/test/java/janggi/domain/piece/JolTest.java index 2f2246be73..9f982de1a6 100644 --- a/src/test/java/janggi/domain/piece/JolTest.java +++ b/src/test/java/janggi/domain/piece/JolTest.java @@ -1,6 +1,5 @@ package janggi.domain.piece; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import janggi.domain.point.Point; diff --git a/src/test/java/janggi/domain/piece/MaTest.java b/src/test/java/janggi/domain/piece/MaTest.java index bd0fb521f4..f3c7a303b6 100644 --- a/src/test/java/janggi/domain/piece/MaTest.java +++ b/src/test/java/janggi/domain/piece/MaTest.java @@ -4,8 +4,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -20,10 +20,10 @@ void straight_back_route() { Point to = Point.of(2, 1); // when - List route = ma.getRoute(from, to); + Route route = ma.getRoute(from, to); // then - assertThat(route.size()).isEqualTo(1); + assertThat(route.getRoutes().size()).isEqualTo(1); } @Test @@ -35,10 +35,10 @@ void left_right_route() { Point to = Point.of(1, 2); // when - List route = ma.getRoute(from, to); + Route route = ma.getRoute(from, to); // then - assertThat(route.size()).isEqualTo(1); + assertThat(route.getRoutes().size()).isEqualTo(1); } @Test diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index 1cc55c3e35..13dc2f36ab 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -5,6 +5,7 @@ import janggi.domain.Board; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.LinkedHashMap; import java.util.List; @@ -41,10 +42,10 @@ void straight_back_route(int x, int y, int result) { Point to = Point.of(x, y); // when - List route = pho.getRoute(from, to); + Route route = pho.getRoute(from, to); // then - assertThat(route.size()).isEqualTo(result); + assertThat(route.getRoutes().size()).isEqualTo(result); } @Test @@ -69,7 +70,7 @@ void can_pho_move() { Point to = Point.of(1, 3); // when - List route = pho.getRoute(from, to); + Route route = pho.getRoute(from, to); List pieces = board.getPieces(route); // then @@ -85,7 +86,7 @@ void can_not_pho_move() { Point to = Point.of(1, 4); // when - List route = pho.getRoute(from, to); + Route route = pho.getRoute(from, to); List pieces = board.getPieces(route); // then @@ -101,7 +102,7 @@ void huddle_is_pho_can_not_move() { Point to = Point.of(1, 7); // when - List route = pho.getRoute(from, to); + Route route = pho.getRoute(from, to); List pieces = board.getPieces(route); // then diff --git a/src/test/java/janggi/domain/piece/SangTest.java b/src/test/java/janggi/domain/piece/SangTest.java index 9ce6474370..b6717e6c6b 100644 --- a/src/test/java/janggi/domain/piece/SangTest.java +++ b/src/test/java/janggi/domain/piece/SangTest.java @@ -4,8 +4,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.point.Point; +import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -23,10 +23,10 @@ void straight_back_route(int column, int row) { Point to = Point.of(column, row); // when - List route = sang.getRoute(from, to); + Route route = sang.getRoute(from, to); // then - assertThat(route.size()).isEqualTo(2); + assertThat(route.getRoutes().size()).isEqualTo(2); } @Test From 1aa202e4d53d7a42d3ff9d31370b02808963de73 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 16:39:56 +0900 Subject: [PATCH 004/110] =?UTF-8?q?refactor(Route):=20Points=EC=99=80=20Ro?= =?UTF-8?q?ute=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/Board.java | 11 ++++++----- src/main/java/janggi/domain/piece/AbstractPiece.java | 6 +++--- src/main/java/janggi/domain/piece/Cha.java | 6 +++--- src/main/java/janggi/domain/piece/Jang.java | 9 +++++---- src/main/java/janggi/domain/piece/Jol.java | 9 +++++---- src/main/java/janggi/domain/piece/Ma.java | 8 ++++---- src/main/java/janggi/domain/piece/Pho.java | 11 ++++++----- src/main/java/janggi/domain/piece/Sa.java | 10 +++++----- src/main/java/janggi/domain/piece/Sang.java | 8 ++++---- 9 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/Board.java index 6fb3b2f85d..b93a9a2554 100644 --- a/src/main/java/janggi/domain/Board.java +++ b/src/main/java/janggi/domain/Board.java @@ -3,6 +3,7 @@ import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.LinkedHashMap; @@ -34,8 +35,8 @@ public void move(Point from, Point to, Team team) { if (targetPiece != null && !piece.canCapture(targetPiece)) { throw new IllegalArgumentException("[ERROR] 이 기물은 해당 타겟을 잡을 수 없습니다."); } - Route route = piece.getRoute(from, to); - if (!piece.canMove(getPieces(route))) { + Points route = piece.getRoutePoints(from, to); + if (!piece.canMove(getRoute(route))) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 경로에 장애물이 있거나 규칙에 어긋납니다."); } pieces.remove(from); @@ -57,11 +58,11 @@ public List> getPoints() { ).toList(); } - public List getPieces(Route point) { - return point.getRoutes().stream() + public Route getRoute(Points points) { + return new Route(points.getPoints().stream() .map(pieces::get) .filter(Objects::nonNull) - .toList(); + .toList()); } private void validateFromPoint(Point from, Team team) { diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java index 712d77fd22..c554d74041 100644 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -1,9 +1,9 @@ package janggi.domain.piece; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; abstract class AbstractPiece implements Piece { @@ -16,7 +16,7 @@ public AbstractPiece(Team team, PieceType type) { } @Override - public abstract Route getRoute(Point from, Point to); + public abstract Points getRoutePoints(Point from, Point to); @Override public boolean canCapture(Piece target) { @@ -24,7 +24,7 @@ public boolean canCapture(Piece target) { } @Override - public boolean canMove(List route) { + public boolean canMove(Route route) { return route.isEmpty(); } diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index da96eae525..bd4378ebb4 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -3,7 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; -import janggi.domain.point.Route; +import janggi.domain.point.Points; import janggi.domain.status.Team; import java.util.ArrayList; import java.util.List; @@ -15,7 +15,7 @@ public Cha(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); @@ -35,6 +35,6 @@ public Route getRoute(Point from, Point to) { int nextY = from.getRow() + (signY * i); route.add(Point.of(nextX, nextY)); } - return new Route(route); + return new Points(route); } } diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index d2fe24d67a..10cac42804 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -16,7 +17,7 @@ public Jang(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -25,11 +26,11 @@ public Route getRoute(Point from, Point to) { if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return new Route(List.of(to)); + return new Points(List.of(to)); } @Override - public boolean canMove(List route) { - return route.stream().noneMatch(piece -> piece.isSameTeam(super.getTeam())); + public boolean canMove(Route route) { + return !route.hasAlly(super.getTeam()); } } diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index fb59f5bd5e..c60fee19df 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -16,7 +17,7 @@ public Jol(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int signY = Integer.compare(pathY, 0); @@ -29,11 +30,11 @@ public Route getRoute(Point from, Point to) { if ((super.getTeam().equals(Team.CHO) && signY < 0) || (super.getTeam().equals(Team.HAN) && signY > 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return new Route(List.of(to)); + return new Points(List.of(to)); } @Override - public boolean canMove(List route) { - return route.stream().noneMatch(piece -> piece.isSameTeam(super.getTeam())); + public boolean canMove(Route route) { + return !route.hasAlly(super.getTeam()); } } diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index db8cbcd169..dfced257bc 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -3,7 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; -import janggi.domain.point.Route; +import janggi.domain.point.Points; import janggi.domain.status.Team; import java.util.List; @@ -17,7 +17,7 @@ public Ma(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -28,8 +28,8 @@ public Route getRoute(Point from, Point to) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } if (distanceX == LONG_STEP) { - return new Route(List.of(Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()))); + return new Points(List.of(Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()))); } - return new Route(List.of(Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)))); + return new Points(List.of(Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)))); } } diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index 4ad7cd516b..18091d2237 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.ArrayList; @@ -15,7 +16,7 @@ public Pho(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); @@ -35,15 +36,15 @@ public Route getRoute(Point from, Point to) { int nextY = from.getRow() + (signY * i); route.add(Point.of(nextX, nextY)); } - return new Route(route); + return new Points(route); } @Override - public boolean canMove(List route) { - if (route.size() > 1) { + public boolean canMove(Route route) { + if (route.hasObstacle()) { return false; } - return route.stream().anyMatch(piece -> !piece.isSameType(PieceType.PHO)); + return !route.hasSameType(PieceType.PHO); } @Override diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index 1b9f95fcfc..f1533d0e1d 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -3,6 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.List; @@ -16,7 +17,7 @@ public Sa(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -25,12 +26,11 @@ public Route getRoute(Point from, Point to) { if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return new Route(List.of(to)); + return new Points(List.of(to)); } @Override - public boolean canMove(List route) { - return route.stream() - .noneMatch(piece -> piece.isSameTeam(super.getTeam())); + public boolean canMove(Route route) { + return !route.hasAlly(super.getTeam()); } } diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index 0633c53f6d..c46e82864f 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -3,7 +3,7 @@ import static java.lang.Math.abs; import janggi.domain.point.Point; -import janggi.domain.point.Route; +import janggi.domain.point.Points; import janggi.domain.status.Team; import java.util.List; @@ -17,7 +17,7 @@ public Sang(Team team) { } @Override - public Route getRoute(Point from, Point to) { + public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); int distanceX = abs(pathX); @@ -30,12 +30,12 @@ public Route getRoute(Point from, Point to) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } if (distanceX == LONG_STEP) { - return new Route(List.of( + return new Points(List.of( Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()), Point.of(from.getColumn() + signX * SHORT_STEP, from.getRow() + signY) )); } - return new Route(List.of( + return new Points(List.of( Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)), Point.of(from.getColumn() + signX, from.getRow() + signY * SHORT_STEP) )); From 5a5da7719a0b1021578ee26abd505fb68742d950 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 16:40:29 +0900 Subject: [PATCH 005/110] =?UTF-8?q?test(Route):=20Points=EC=99=80=20Route?= =?UTF-8?q?=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/piece/ChaTest.java | 7 +++--- .../java/janggi/domain/piece/JangTest.java | 2 +- .../java/janggi/domain/piece/JolTest.java | 6 ++--- src/test/java/janggi/domain/piece/MaTest.java | 11 +++++---- .../java/janggi/domain/piece/PhoTest.java | 24 +++++++++---------- src/test/java/janggi/domain/piece/SaTest.java | 2 +- .../java/janggi/domain/piece/SangTest.java | 8 +++---- 7 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/test/java/janggi/domain/piece/ChaTest.java b/src/test/java/janggi/domain/piece/ChaTest.java index 177e9ec41e..9839a692a8 100644 --- a/src/test/java/janggi/domain/piece/ChaTest.java +++ b/src/test/java/janggi/domain/piece/ChaTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; @@ -23,10 +24,10 @@ void straight_back_route(int x, int y, int result) { Point to = Point.of(x, y); // when - Route route = cha.getRoute(from, to); + Points points = cha.getRoutePoints(from, to); // then - assertThat(route.getRoutes().size()).isEqualTo(result); + assertThat(points.getPoints().size()).isEqualTo(result); } @Test @@ -38,7 +39,7 @@ void destination_exception() { Point to = Point.of(7, 1); // when & then - assertThatThrownBy(() -> cha.getRoute(from, to)) + assertThatThrownBy(() -> cha.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/janggi/domain/piece/JangTest.java b/src/test/java/janggi/domain/piece/JangTest.java index 5f98523115..15be41f934 100644 --- a/src/test/java/janggi/domain/piece/JangTest.java +++ b/src/test/java/janggi/domain/piece/JangTest.java @@ -18,7 +18,7 @@ void destination_exception() { Point to = Point.of(7, 1); // when & then - assertThatThrownBy(() -> jang.getRoute(from, to)) + assertThatThrownBy(() -> jang.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/janggi/domain/piece/JolTest.java b/src/test/java/janggi/domain/piece/JolTest.java index 9f982de1a6..8edc094497 100644 --- a/src/test/java/janggi/domain/piece/JolTest.java +++ b/src/test/java/janggi/domain/piece/JolTest.java @@ -18,7 +18,7 @@ void cho_can_move() { Point to = Point.of(3,2); // when & then - assertThatThrownBy(() -> piece.getRoute(from, to)) + assertThatThrownBy(() -> piece.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } @@ -31,7 +31,7 @@ void han_can_move() { Point to = Point.of(3,4); // when & then - assertThatThrownBy(() -> piece.getRoute(from, to)) + assertThatThrownBy(() -> piece.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } @@ -44,7 +44,7 @@ void destination_exception() { Point to = Point.of(7, 1); // when & then - assertThatThrownBy(() -> jol.getRoute(from, to)) + assertThatThrownBy(() -> jol.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/janggi/domain/piece/MaTest.java b/src/test/java/janggi/domain/piece/MaTest.java index f3c7a303b6..f86a423268 100644 --- a/src/test/java/janggi/domain/piece/MaTest.java +++ b/src/test/java/janggi/domain/piece/MaTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; @@ -20,10 +21,10 @@ void straight_back_route() { Point to = Point.of(2, 1); // when - Route route = ma.getRoute(from, to); + Points route = ma.getRoutePoints(from, to); // then - assertThat(route.getRoutes().size()).isEqualTo(1); + assertThat(route.getPoints().size()).isEqualTo(1); } @Test @@ -35,10 +36,10 @@ void left_right_route() { Point to = Point.of(1, 2); // when - Route route = ma.getRoute(from, to); + Points route = ma.getRoutePoints(from, to); // then - assertThat(route.getRoutes().size()).isEqualTo(1); + assertThat(route.getPoints().size()).isEqualTo(1); } @Test @@ -50,7 +51,7 @@ void destination_exception() { Point to = Point.of(1, 1); // when & then - assertThatThrownBy(() -> ma.getRoute(from, to)) + assertThatThrownBy(() -> ma.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index 13dc2f36ab..80581812f0 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -5,10 +5,10 @@ import janggi.domain.Board; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -42,10 +42,10 @@ void straight_back_route(int x, int y, int result) { Point to = Point.of(x, y); // when - Route route = pho.getRoute(from, to); + Points points = pho.getRoutePoints(from, to); // then - assertThat(route.getRoutes().size()).isEqualTo(result); + assertThat(points.getPoints().size()).isEqualTo(result); } @Test @@ -57,7 +57,7 @@ void destination_exception() { Point to = Point.of(1, 1); // when & then - assertThatThrownBy(() -> pho.getRoute(from, to)) + assertThatThrownBy(() -> pho.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } @@ -70,11 +70,11 @@ void can_pho_move() { Point to = Point.of(1, 3); // when - Route route = pho.getRoute(from, to); - List pieces = board.getPieces(route); + Points points = pho.getRoutePoints(from, to); + Route route = board.getRoute(points); // then - assertThat(pho.canMove(pieces)).isTrue(); + assertThat(pho.canMove(route)).isTrue(); } @Test @@ -86,11 +86,11 @@ void can_not_pho_move() { Point to = Point.of(1, 4); // when - Route route = pho.getRoute(from, to); - List pieces = board.getPieces(route); + Points points = pho.getRoutePoints(from, to); + Route route = board.getRoute(points); // then - assertThat(pho.canMove(pieces)).isFalse(); + assertThat(pho.canMove(route)).isFalse(); } @Test @@ -102,8 +102,8 @@ void huddle_is_pho_can_not_move() { Point to = Point.of(1, 7); // when - Route route = pho.getRoute(from, to); - List pieces = board.getPieces(route); + Points points = pho.getRoutePoints(from, to); + Route pieces = board.getRoute(points); // then assertThat(pho.canMove(pieces)).isFalse(); diff --git a/src/test/java/janggi/domain/piece/SaTest.java b/src/test/java/janggi/domain/piece/SaTest.java index 36d3d7c0c5..de21623269 100644 --- a/src/test/java/janggi/domain/piece/SaTest.java +++ b/src/test/java/janggi/domain/piece/SaTest.java @@ -18,7 +18,7 @@ void destination_exception() { Point to = Point.of(7, 1); // when & then - assertThatThrownBy(() -> sa.getRoute(from, to)) + assertThatThrownBy(() -> sa.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/janggi/domain/piece/SangTest.java b/src/test/java/janggi/domain/piece/SangTest.java index b6717e6c6b..c3d3e373db 100644 --- a/src/test/java/janggi/domain/piece/SangTest.java +++ b/src/test/java/janggi/domain/piece/SangTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.point.Point; -import janggi.domain.point.Route; +import janggi.domain.point.Points; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -23,10 +23,10 @@ void straight_back_route(int column, int row) { Point to = Point.of(column, row); // when - Route route = sang.getRoute(from, to); + Points points = sang.getRoutePoints(from, to); // then - assertThat(route.getRoutes().size()).isEqualTo(2); + assertThat(points.getPoints().size()).isEqualTo(2); } @Test @@ -38,7 +38,7 @@ void destination_exception() { Point to = Point.of(1, 1); // when & then - assertThatThrownBy(() -> sang.getRoute(from, to)) + assertThatThrownBy(() -> sang.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } } From aa9a62f340e247b33d31b992262011ae743c06af Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 16:41:42 +0900 Subject: [PATCH 006/110] =?UTF-8?q?refactor(Route):=20Points=EC=99=80=20Ro?= =?UTF-8?q?ute=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Piece.java | 6 ++--- src/main/java/janggi/domain/point/Points.java | 17 ++++++++++++ src/main/java/janggi/domain/point/Route.java | 26 ++++++++++++++----- 3 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 src/main/java/janggi/domain/point/Points.java diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 97ef38d18e..e3b75caa95 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -1,14 +1,14 @@ package janggi.domain.piece; import janggi.domain.point.Point; +import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; public interface Piece { - Route getRoute(Point from, Point to); + Points getRoutePoints(Point from, Point to); PieceType getType(); - boolean canMove(List route); + boolean canMove(Route route); boolean isSameTeam(Team team); boolean isSameType(PieceType type); boolean canCapture(Piece target); diff --git a/src/main/java/janggi/domain/point/Points.java b/src/main/java/janggi/domain/point/Points.java new file mode 100644 index 0000000000..87ef7ebda7 --- /dev/null +++ b/src/main/java/janggi/domain/point/Points.java @@ -0,0 +1,17 @@ +package janggi.domain.point; + +import java.util.Collections; +import java.util.List; + +public class Points { + + private final List points; + + public Points(List points) { + this.points = points; + } + + public List getPoints() { + return Collections.unmodifiableList(points); + } +} diff --git a/src/main/java/janggi/domain/point/Route.java b/src/main/java/janggi/domain/point/Route.java index 8fbc4a5022..176277abd0 100644 --- a/src/main/java/janggi/domain/point/Route.java +++ b/src/main/java/janggi/domain/point/Route.java @@ -1,17 +1,31 @@ package janggi.domain.point; -import java.util.Collections; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; +import janggi.domain.status.Team; import java.util.List; public class Route { - private final List points; + private final List pieces; - public Route(List points) { - this.points = points; + public Route(List pieces) { + this.pieces = pieces; } - public List getRoutes() { - return Collections.unmodifiableList(points); + public boolean isEmpty() { + return pieces.isEmpty(); + } + + public boolean hasObstacle() { + return pieces.size() > 1; + } + + public boolean hasSameType(PieceType type) { + return pieces.stream().anyMatch(piece -> !piece.isSameType(type)); + } + + public boolean hasAlly(Team team) { + return pieces.stream().anyMatch(piece -> piece.isSameTeam(team)); } } From 0f1da61ae3fb862b3384845196fcf58f31f86c35 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 16:44:37 +0900 Subject: [PATCH 007/110] =?UTF-8?q?refactor(PositionInfo):=20col,=20row=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/presentation/dto/PositionInfo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/presentation/dto/PositionInfo.java b/src/main/java/janggi/presentation/dto/PositionInfo.java index b9551fcf6b..4d89fc230b 100644 --- a/src/main/java/janggi/presentation/dto/PositionInfo.java +++ b/src/main/java/janggi/presentation/dto/PositionInfo.java @@ -10,10 +10,10 @@ public record PositionInfo( Piece piece, Point point ) { - public static PositionInfo from(Team team, String pieceName, int x, int y) { + public static PositionInfo from(Team team, String pieceName, int column, int row) { return new PositionInfo( PieceFactory.createPiece(team, PieceType.valueOf(pieceName)), - Point.of(x, y) + Point.of(column, row) ); } } From fd63ca39e185e5ea17837d07ae4f231062bb5caa Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 17:35:29 +0900 Subject: [PATCH 008/110] =?UTF-8?q?fix(Route):=20boolean=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=EA=B0=92=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/point/Route.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/point/Route.java b/src/main/java/janggi/domain/point/Route.java index 176277abd0..3d287b041f 100644 --- a/src/main/java/janggi/domain/point/Route.java +++ b/src/main/java/janggi/domain/point/Route.java @@ -22,7 +22,7 @@ public boolean hasObstacle() { } public boolean hasSameType(PieceType type) { - return pieces.stream().anyMatch(piece -> !piece.isSameType(type)); + return pieces.stream().anyMatch(piece -> piece.isSameType(type)); } public boolean hasAlly(Team team) { From 4f41b5593aecf908eef9913c7e749cfe6bfb5f8d Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 17:43:48 +0900 Subject: [PATCH 009/110] =?UTF-8?q?refactor(Board):=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=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 --- src/main/java/janggi/domain/Board.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/Board.java index b93a9a2554..359f696657 100644 --- a/src/main/java/janggi/domain/Board.java +++ b/src/main/java/janggi/domain/Board.java @@ -35,8 +35,8 @@ public void move(Point from, Point to, Team team) { if (targetPiece != null && !piece.canCapture(targetPiece)) { throw new IllegalArgumentException("[ERROR] 이 기물은 해당 타겟을 잡을 수 없습니다."); } - Points route = piece.getRoutePoints(from, to); - if (!piece.canMove(getRoute(route))) { + Points points = piece.getRoutePoints(from, to); + if (!piece.canMove(getRoute(points))) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 경로에 장애물이 있거나 규칙에 어긋납니다."); } pieces.remove(from); From 506a3188aca30c6675489b2a7f74f73a5feebb95 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 17:44:11 +0900 Subject: [PATCH 010/110] =?UTF-8?q?refactor(Route):=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=20=EB=84=98=EB=B2=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/point/Route.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/janggi/domain/point/Route.java b/src/main/java/janggi/domain/point/Route.java index 3d287b041f..7883f87b48 100644 --- a/src/main/java/janggi/domain/point/Route.java +++ b/src/main/java/janggi/domain/point/Route.java @@ -7,6 +7,8 @@ public class Route { + private static final int OBSTACLE_SIZE = 1; + private final List pieces; public Route(List pieces) { @@ -18,14 +20,16 @@ public boolean isEmpty() { } public boolean hasObstacle() { - return pieces.size() > 1; + return pieces.size() > OBSTACLE_SIZE; } public boolean hasSameType(PieceType type) { - return pieces.stream().anyMatch(piece -> piece.isSameType(type)); + return pieces.stream() + .anyMatch(piece -> piece.isSameType(type)); } public boolean hasAlly(Team team) { - return pieces.stream().anyMatch(piece -> piece.isSameTeam(team)); + return pieces.stream() + .anyMatch(piece -> piece.isSameTeam(team)); } } From 2ee2313c7687ccd4b9ca4b166cdf802ed98754ce Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 18:05:21 +0900 Subject: [PATCH 011/110] =?UTF-8?q?refactor(Piece):=20=EC=88=98=ED=95=99?= =?UTF-8?q?=EC=A0=81=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=EC=9D=84=20?= =?UTF-8?q?=EB=B0=A9=ED=96=A5=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Ma.java | 19 ++----- src/main/java/janggi/domain/piece/Sang.java | 35 +++++------- .../domain/piece/direction/MaDirection.java | 41 ++++++++++++++ .../domain/piece/direction/SangDirection.java | 54 +++++++++++++++++++ src/test/java/janggi/domain/BoardTest.java | 2 +- 5 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 src/main/java/janggi/domain/piece/direction/MaDirection.java create mode 100644 src/main/java/janggi/domain/piece/direction/SangDirection.java diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index dfced257bc..96500cb168 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -1,7 +1,6 @@ package janggi.domain.piece; -import static java.lang.Math.abs; - +import janggi.domain.piece.direction.MaDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; @@ -9,9 +8,6 @@ public class Ma extends AbstractPiece { - private static final int LONG_STEP = 2; - private static final int SHORT_STEP = 1; - public Ma(Team team) { super(team, PieceType.MA); } @@ -20,16 +16,9 @@ public Ma(Team team) { public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); - int distanceX = abs(pathX); - int distanceY = abs(pathY); - if (!((distanceX == LONG_STEP && distanceY == SHORT_STEP) || - (distanceX == SHORT_STEP && distanceY == LONG_STEP))) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } - if (distanceX == LONG_STEP) { - return new Points(List.of(Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()))); - } - return new Points(List.of(Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)))); + MaDirection direction = MaDirection.find(pathX, pathY); + Point point = Point.of(from.getColumn() + direction.getRouteCol(), from.getRow() + direction.getRouteRow()); + return new Points(List.of(point)); } } diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index c46e82864f..26090d65d4 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -1,7 +1,6 @@ package janggi.domain.piece; -import static java.lang.Math.abs; - +import janggi.domain.piece.direction.SangDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; @@ -9,9 +8,6 @@ public class Sang extends AbstractPiece { - private static final int LONG_STEP = 3; - private static final int SHORT_STEP = 2; - public Sang(Team team) { super(team, PieceType.SANG); } @@ -20,24 +16,17 @@ public Sang(Team team) { public Points getRoutePoints(Point from, Point to) { int pathX = to.calculatePathColumn(from); int pathY = to.calculatePathRow(from); - int distanceX = abs(pathX); - int distanceY = abs(pathY); - int signX = Integer.compare(pathX, 0); - int signY = Integer.compare(pathY, 0); - if (!((distanceX == LONG_STEP && distanceY == SHORT_STEP) || - (distanceX == SHORT_STEP && distanceY == LONG_STEP))) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } - if (distanceX == LONG_STEP) { - return new Points(List.of( - Point.of(from.getColumn() + (pathX / LONG_STEP), from.getRow()), - Point.of(from.getColumn() + signX * SHORT_STEP, from.getRow() + signY) - )); - } - return new Points(List.of( - Point.of(from.getColumn(), from.getRow() + (pathY / LONG_STEP)), - Point.of(from.getColumn() + signX, from.getRow() + signY * SHORT_STEP) - )); + SangDirection direction = SangDirection.find(pathX, pathY); + + Point routePoint1 = Point.of( + from.getColumn() + direction.getRoute1Col(), + from.getRow() + direction.getRoute1Row() + ); + Point routePoint2 = Point.of(from.getColumn() + direction.getRoute2Col(), + from.getRow() + direction.getRoute2Row() + ); + + return new Points(List.of(routePoint1, routePoint2)); } } diff --git a/src/main/java/janggi/domain/piece/direction/MaDirection.java b/src/main/java/janggi/domain/piece/direction/MaDirection.java new file mode 100644 index 0000000000..7e3faa55d2 --- /dev/null +++ b/src/main/java/janggi/domain/piece/direction/MaDirection.java @@ -0,0 +1,41 @@ +package janggi.domain.piece.direction; + +import java.util.Arrays; + +public enum MaDirection { + UP_LEFT(-1, -2, 0, -1), + UP_RIGHT(1, -2, 0, -1), + DOWN_LEFT(-1, 2, 0, 1), + DOWN_RIGHT(1, 2, 0, 1), + LEFT_UP(-2, -1, -1, 0), + LEFT_DOWN(-2, 1, -1, 0), + RIGHT_UP(2, -1, 1, 0), + RIGHT_DOWN(2, 1, 1, 0); + + private final int targetCol; + private final int targetRow; + private final int routeCol; + private final int routeRow; + + MaDirection(int targetCol, int targetRow, int routeCol, int routeRow) { + this.targetCol = targetCol; + this.targetRow = targetRow; + this.routeCol = routeCol; + this.routeRow = routeRow; + } + + public static MaDirection find(int directionCol, int directionRow) { + return Arrays.stream(values()) + .filter(dir -> dir.targetCol == directionCol && dir.targetRow == directionRow) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 마가 이동할 수 없는 방향입니다.")); + } + + public int getRouteCol() { + return routeCol; + } + + public int getRouteRow() { + return routeRow; + } +} diff --git a/src/main/java/janggi/domain/piece/direction/SangDirection.java b/src/main/java/janggi/domain/piece/direction/SangDirection.java new file mode 100644 index 0000000000..2d234ae271 --- /dev/null +++ b/src/main/java/janggi/domain/piece/direction/SangDirection.java @@ -0,0 +1,54 @@ +package janggi.domain.piece.direction; + +import java.util.Arrays; + +public enum SangDirection { + UP_LEFT(-2, -3, 0, -1, -1, -2), + UP_RIGHT(2, -3, 0, -1, 1, -2), + DOWN_LEFT(-2, 3, 0, 1, -1, 2), + DOWN_RIGHT(2, 3, 0, 1, 1, 2), + + LEFT_UP(-3, -2, -1, 0, -2, -1), + LEFT_DOWN(-3, 2, -1, 0, -2, 1), + RIGHT_UP(3, -2, 1, 0, 2, -1), + RIGHT_DOWN(3, 2, 1, 0, 2, 1); + + private final int targetCol; + private final int targetRow; + private final int route1Col; + private final int route1Row; + private final int route2Col; + private final int route2Row; + + SangDirection(int targetCol, int targetRow, int route1Col, int route1Row, int route2Col, int route2Row) { + this.targetCol = targetCol; + this.targetRow = targetRow; + this.route1Col = route1Col; + this.route1Row = route1Row; + this.route2Col = route2Col; + this.route2Row = route2Row; + } + + public static SangDirection find(int directionCol, int directionRow) { + return Arrays.stream(values()) + .filter(dir -> dir.targetCol == directionCol && dir.targetRow == directionRow) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 상이 이동할 수 없는 방향입니다.")); + } + + public int getRoute1Col() { + return route1Col; + } + + public int getRoute1Row() { + return route1Row; + } + + public int getRoute2Col() { + return route2Col; + } + + public int getRoute2Row() { + return route2Row; + } +} diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 673f913f29..95fb6da57f 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -38,7 +38,7 @@ void can_not_move_rule() { board.init(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(0, 0), Point.of(1, 1), Team.HAN)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + .hasMessageContaining("[ERROR] 마가 이동할 수 없는 방향입니다."); } @Test From ee3d02f8fd9957cc30dbbcba5d5584e7935722e8 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 28 Mar 2026 18:12:19 +0900 Subject: [PATCH 012/110] =?UTF-8?q?refactor(Piece):=20col,row=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cha.java | 18 +++++++++--------- src/main/java/janggi/domain/piece/Jang.java | 10 +++++----- src/main/java/janggi/domain/piece/Jol.java | 14 +++++++------- src/main/java/janggi/domain/piece/Pho.java | 18 +++++++++--------- src/main/java/janggi/domain/piece/Sa.java | 10 +++++----- src/main/java/janggi/domain/piece/Sang.java | 6 +++--- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index bd4378ebb4..70406b6292 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -16,24 +16,24 @@ public Cha(Team team) { @Override public Points getRoutePoints(Point from, Point to) { - int pathX = to.calculatePathColumn(from); - int pathY = to.calculatePathRow(from); + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); - if (pathY != 0 && pathX != 0) { + if (pathRow != 0 && pathCol != 0) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - int signX = Integer.compare(pathX, 0); - int signY = Integer.compare(pathY, 0); + int signCol = Integer.compare(pathCol, 0); + int signRow = Integer.compare(pathRow, 0); - int distance = Math.max(abs(pathX), abs(pathY)); + int distance = Math.max(abs(pathCol), abs(pathRow)); List route = new ArrayList<>(); for (int i = 1; i < distance; i++) { - int nextX = from.getColumn() + (signX * i); - int nextY = from.getRow() + (signY * i); - route.add(Point.of(nextX, nextY)); + int nextCol = from.getColumn() + (signCol * i); + int nextRow = from.getRow() + (signRow * i); + route.add(Point.of(nextCol, nextRow)); } return new Points(route); } diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index 10cac42804..50d105f30d 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -18,12 +18,12 @@ public Jang(Team team) { @Override public Points getRoutePoints(Point from, Point to) { - int pathX = to.calculatePathColumn(from); - int pathY = to.calculatePathRow(from); - int distanceX = abs(pathX); - int distanceY = abs(pathY); + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); + int distanceCol = abs(pathCol); + int distanceRow = abs(pathRow); - if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } return new Points(List.of(to)); diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index c60fee19df..d7cb203f40 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -18,16 +18,16 @@ public Jol(Team team) { @Override public Points getRoutePoints(Point from, Point to) { - int pathX = to.calculatePathColumn(from); - int pathY = to.calculatePathRow(from); - int signY = Integer.compare(pathY, 0); - int distanceX = abs(pathX); - int distanceY = abs(pathY); + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); + int signRow = Integer.compare(pathRow, 0); + int distanceCol = abs(pathCol); + int distanceRow = abs(pathRow); - if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX + distanceY > MAX_DISTANCE)) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol + distanceRow > MAX_DISTANCE)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - if ((super.getTeam().equals(Team.CHO) && signY < 0) || (super.getTeam().equals(Team.HAN) && signY > 0)) { + if ((super.getTeam().equals(Team.CHO) && signRow < 0) || (super.getTeam().equals(Team.HAN) && signRow > 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } return new Points(List.of(to)); diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index 18091d2237..f34241f9c5 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -17,24 +17,24 @@ public Pho(Team team) { @Override public Points getRoutePoints(Point from, Point to) { - int pathX = to.calculatePathColumn(from); - int pathY = to.calculatePathRow(from); + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); - if (pathY != 0 && pathX != 0) { + if (pathRow != 0 && pathCol != 0) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - int signX = Integer.compare(pathX, 0); - int signY = Integer.compare(pathY, 0); + int signCol = Integer.compare(pathCol, 0); + int signRow = Integer.compare(pathRow, 0); - int distance = Math.max(abs(pathX), abs(pathY)); + int distance = Math.max(abs(pathCol), abs(pathRow)); List route = new ArrayList<>(); for (int i = 1; i < distance; i++) { - int nextX = from.getColumn() + (signX * i); - int nextY = from.getRow() + (signY * i); - route.add(Point.of(nextX, nextY)); + int nextCol = from.getColumn() + (signCol * i); + int nextRow = from.getRow() + (signRow * i); + route.add(Point.of(nextCol, nextRow)); } return new Points(route); } diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index f1533d0e1d..bc3b1f39e0 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -18,12 +18,12 @@ public Sa(Team team) { @Override public Points getRoutePoints(Point from, Point to) { - int pathX = to.calculatePathColumn(from); - int pathY = to.calculatePathRow(from); - int distanceX = abs(pathX); - int distanceY = abs(pathY); + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); + int distanceCol = abs(pathCol); + int distanceRow = abs(pathRow); - if (distanceX > MAX_DISTANCE || distanceY > MAX_DISTANCE || (distanceX == 0 && distanceY == 0)) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } return new Points(List.of(to)); diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index 26090d65d4..54f30f1c35 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -14,10 +14,10 @@ public Sang(Team team) { @Override public Points getRoutePoints(Point from, Point to) { - int pathX = to.calculatePathColumn(from); - int pathY = to.calculatePathRow(from); + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); - SangDirection direction = SangDirection.find(pathX, pathY); + SangDirection direction = SangDirection.find(pathCol, pathRow); Point routePoint1 = Point.of( from.getColumn() + direction.getRoute1Col(), From 1d3c1bf632a9b1dc8b52066e3127db9e58fdae4b Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 15:54:46 +0900 Subject: [PATCH 013/110] =?UTF-8?q?test(Cha):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EC=95=88=EC=97=90=EC=84=9C=20=EC=9B=80=EC=A7=81=EC=9E=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=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/piece/ChaTest.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/java/janggi/domain/piece/ChaTest.java b/src/test/java/janggi/domain/piece/ChaTest.java index 9839a692a8..236efb0233 100644 --- a/src/test/java/janggi/domain/piece/ChaTest.java +++ b/src/test/java/janggi/domain/piece/ChaTest.java @@ -5,7 +5,6 @@ import janggi.domain.point.Point; import janggi.domain.point.Points; -import janggi.domain.point.Route; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -42,4 +41,16 @@ void destination_exception() { assertThatThrownBy(() -> cha.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } + + @ParameterizedTest + @DisplayName("궁성 안에서 이동 할 경우 대각선으로 이동 할 수 있다.") + @CsvSource(value = {"3:0:5:2:4:1","3:7:5:9:4:8","3:9:5:7:4:8"}, delimiter = ':') + void can_move_diagonal(int fromColumn, int fromRow, int toColumn, int toRow, int routeColumn, int routeRow) { + Piece cha = new Cha(Team.CHO); + Point from = Point.of(fromColumn, fromRow); + Point to = Point.of(toColumn, toRow); + Points routePoints = cha.getRoutePoints(from, to); + assertThat(routePoints.getPoints().getFirst().getColumn()).isEqualTo(routeColumn); + assertThat(routePoints.getPoints().getFirst().getRow()).isEqualTo(routeRow); + } } From c128726c30d89d7b8d2bff1172d2f1f55cba4d4f Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 15:55:04 +0900 Subject: [PATCH 014/110] =?UTF-8?q?feat(Cha):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EC=95=88=EC=97=90=EC=84=9C=20=EC=9B=80=EC=A7=81=EC=9E=84=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cha.java | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index 70406b6292..301cc0cd98 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; @@ -18,23 +19,27 @@ public Cha(Team team) { public Points getRoutePoints(Point from, Point to) { int pathCol = to.calculatePathColumn(from); int pathRow = to.calculatePathRow(from); - + int signCol = Integer.compare(pathCol, 0); + int signRow = Integer.compare(pathRow, 0); + List points = new ArrayList<>(); + if (from.inSameCastle(to)) { + CastleDirection castleDirection = CastleDirection.find(from, signCol, signRow); + points.add(Point.of( + from.getColumn() + castleDirection.getTargetCol(), + from.getRow() + castleDirection.getTargetRow() + ) + ); + return new Points(points); + } if (pathRow != 0 && pathCol != 0) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - - int signCol = Integer.compare(pathCol, 0); - int signRow = Integer.compare(pathRow, 0); - int distance = Math.max(abs(pathCol), abs(pathRow)); - - List route = new ArrayList<>(); - for (int i = 1; i < distance; i++) { int nextCol = from.getColumn() + (signCol * i); int nextRow = from.getRow() + (signRow * i); - route.add(Point.of(nextCol, nextRow)); + points.add(Point.of(nextCol, nextRow)); } - return new Points(route); + return new Points(points); } } From f9952c77d1c0f12825bc33276c25f1b2a6ae5a34 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 15:55:21 +0900 Subject: [PATCH 015/110] =?UTF-8?q?test(Pho):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EC=95=88=EC=97=90=EC=84=9C=20=EC=9B=80=EC=A7=81=EC=9E=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=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/piece/PhoTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index 80581812f0..adde68d717 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -108,4 +108,16 @@ void huddle_is_pho_can_not_move() { // then assertThat(pho.canMove(pieces)).isFalse(); } + + @ParameterizedTest + @DisplayName("궁성 안에서는 대각선으로 이동 할 수 있다.") + @CsvSource(value = {"3:0:5:2:4:1","3:7:5:9:4:8","3:9:5:7:4:8"}, delimiter = ':') + void can_move_diagonal(int fromColumn, int fromRow, int toColumn, int toRow, int routeColumn, int routeRow) { + Piece pho = new Pho(Team.HAN); + Point from = Point.of(fromColumn, fromRow); + Point to = Point.of(toColumn, toRow); + Points routePoints = pho.getRoutePoints(from, to); + assertThat(routePoints.getPoints().getFirst().getColumn()).isEqualTo(routeColumn); + assertThat(routePoints.getPoints().getFirst().getRow()).isEqualTo(routeRow); + } } From 6f79f8520fa01b69d74422efb05755dc05103a39 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 15:55:31 +0900 Subject: [PATCH 016/110] =?UTF-8?q?refactor(Pho):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EC=95=88=EC=97=90=EC=84=9C=20=EC=9B=80=EC=A7=81=EC=9E=84=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Pho.java | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index f34241f9c5..a200596077 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; @@ -19,24 +20,28 @@ public Pho(Team team) { public Points getRoutePoints(Point from, Point to) { int pathCol = to.calculatePathColumn(from); int pathRow = to.calculatePathRow(from); - + int signCol = Integer.compare(pathCol, 0); + int signRow = Integer.compare(pathRow, 0); + List points = new ArrayList<>(); + if (from.inSameCastle(to)) { + CastleDirection castleDirection = CastleDirection.find(from, signCol, signRow); + points.add(Point.of( + from.getColumn() + castleDirection.getTargetCol(), + from.getRow() + castleDirection.getTargetRow() + ) + ); + return new Points(points); + } if (pathRow != 0 && pathCol != 0) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - - int signCol = Integer.compare(pathCol, 0); - int signRow = Integer.compare(pathRow, 0); - int distance = Math.max(abs(pathCol), abs(pathRow)); - - List route = new ArrayList<>(); - for (int i = 1; i < distance; i++) { int nextCol = from.getColumn() + (signCol * i); int nextRow = from.getRow() + (signRow * i); - route.add(Point.of(nextCol, nextRow)); + points.add(Point.of(nextCol, nextRow)); } - return new Points(route); + return new Points(points); } @Override From db7292e69690f3ddd434ac09c2445750b2542668 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 15:55:52 +0900 Subject: [PATCH 017/110] =?UTF-8?q?test(Board):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EC=95=88=EC=97=90=EC=84=9C=20=EC=9B=80=EC=A7=81=EC=9E=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=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/BoardTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 95fb6da57f..5a1c1d5151 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -76,4 +76,17 @@ void can_not_catch_piece() { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 이 기물은 해당 타겟을 잡을 수 없습니다."); } + + @Test + @DisplayName("궁성 안에서 차를 움직일 때, (4, 0)에서는 대각선으로 움직일 수 없다.") + void can_move_pho_diagonal() { + Map pieces = new LinkedHashMap<>(); + pieces.put(Point.of(4, 0), new Cha(Team.HAN)); + board.init(pieces); + Assertions.assertThatThrownBy(() -> board.move(Point.of(4, 0), Point.of(5, 1), Team.HAN)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 이동할 수 없는 방향입니다."); + } + + } From 8fc3f25dd7325efd0e78ccacb2db00cd615b1b16 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 15:56:29 +0900 Subject: [PATCH 018/110] =?UTF-8?q?feat:=20=EA=B6=81=EC=84=B1=20=EC=95=88?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9B=80=EC=A7=81=EC=9E=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=EB=A7=B5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../piece/direction/CastleDirection.java | 60 +++++++++++++++++++ src/main/java/janggi/domain/point/Point.java | 14 +++++ 2 files changed, 74 insertions(+) create mode 100644 src/main/java/janggi/domain/piece/direction/CastleDirection.java diff --git a/src/main/java/janggi/domain/piece/direction/CastleDirection.java b/src/main/java/janggi/domain/piece/direction/CastleDirection.java new file mode 100644 index 0000000000..5cb4674c0c --- /dev/null +++ b/src/main/java/janggi/domain/piece/direction/CastleDirection.java @@ -0,0 +1,60 @@ +package janggi.domain.piece.direction; + +import janggi.domain.point.Point; +import java.util.List; +import java.util.Map; + +public enum CastleDirection { + UP(0, 1), + DOWN(0, -1), + LEFT(-1, 0), + RIGHT(1, 0), + UP_RIGHT(1, 1), + UP_LEFT(-1, 1), + DOWN_RIGHT(1, -1), + DOWN_LEFT(-1, -1); + + private static final Map> RULE = Map.ofEntries( + Map.entry(Point.of(3, 0), List.of(RIGHT, UP, UP_RIGHT)), + Map.entry(Point.of(4, 0), List.of(LEFT, RIGHT, UP)), + Map.entry(Point.of(5, 0), List.of(LEFT, UP, UP_LEFT)), + Map.entry(Point.of(3, 1), List.of(DOWN, RIGHT, UP)), + Map.entry(Point.of(4, 1), List.of(DOWN, DOWN_LEFT, DOWN_RIGHT, LEFT, RIGHT, UP, UP_LEFT, UP_RIGHT)), + Map.entry(Point.of(5, 1), List.of(DOWN, LEFT, UP)), + Map.entry(Point.of(3, 2), List.of(DOWN, DOWN_RIGHT, RIGHT)), + Map.entry(Point.of(4, 2), List.of(DOWN, LEFT, RIGHT)), + Map.entry(Point.of(5, 2), List.of(DOWN, DOWN_LEFT, LEFT)), + Map.entry(Point.of(3, 7), List.of(RIGHT, UP, UP_RIGHT)), + Map.entry(Point.of(4, 7), List.of(LEFT, RIGHT, UP)), + Map.entry(Point.of(5, 7), List.of(LEFT, UP, UP_LEFT)), + Map.entry(Point.of(3, 8), List.of(UP, DOWN, RIGHT)), + Map.entry(Point.of(4, 8), List.of(DOWN, DOWN_LEFT, DOWN_RIGHT, LEFT, RIGHT, UP, UP_LEFT, UP_RIGHT)), + Map.entry(Point.of(5, 8), List.of(UP, DOWN, LEFT)), + Map.entry(Point.of(3, 9), List.of(DOWN, DOWN_RIGHT, RIGHT)), + Map.entry(Point.of(4, 9), List.of(LEFT, RIGHT, DOWN)), + Map.entry(Point.of(5, 9), List.of(DOWN, DOWN_LEFT, LEFT)) + ); + + private final int targetCol; + private final int targetRow; + + CastleDirection(int targetCol, int targetRow) { + this.targetCol = targetCol; + this.targetRow = targetRow; + } + + public static CastleDirection find(Point point, int directionCol, int directionRow) { + return RULE.get(point).stream() + .filter(dir -> dir.targetCol == directionCol && dir.targetRow == directionRow) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 이동할 수 없는 방향입니다.")); + } + + public int getTargetCol() { + return targetCol; + } + + public int getTargetRow() { + return targetRow; + } +} diff --git a/src/main/java/janggi/domain/point/Point.java b/src/main/java/janggi/domain/point/Point.java index 7d48b42a67..79b78d7adf 100644 --- a/src/main/java/janggi/domain/point/Point.java +++ b/src/main/java/janggi/domain/point/Point.java @@ -43,6 +43,13 @@ public int calculatePathRow(Point from) { return this.row - from.row; } + public boolean inSameCastle(Point other) { + if (this.isCastle() && other.isCastle()) { + return (this.row <= 2) == (other.row <= 2); + } + return false; + } + public int getColumn() { return col; } @@ -56,4 +63,11 @@ private static void addColumn(List row, int col) { row.add(new Point(i, col)); } } + + private boolean isCastle() { + boolean isColumnCastle = col >= 3 && col <= 5; + boolean isRowTopCastle = row >= 7 && row <= 9; + boolean isRowBottomCastle = row <= 2 && row >= 0; + return isColumnCastle && (isRowTopCastle || isRowBottomCastle); + } } From 5c2096f0b83c19f0820d0800cabf4dc6b8f8e655 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:03:13 +0900 Subject: [PATCH 019/110] =?UTF-8?q?test(jang&sa):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EB=B0=96=EC=9C=BC=EB=A1=9C=20=EB=AA=BB=EB=82=98=EA=B0=90=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=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/piece/JangTest.java | 12 ++++++++++++ src/test/java/janggi/domain/piece/SaTest.java | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/test/java/janggi/domain/piece/JangTest.java b/src/test/java/janggi/domain/piece/JangTest.java index 15be41f934..d5ce39e0fd 100644 --- a/src/test/java/janggi/domain/piece/JangTest.java +++ b/src/test/java/janggi/domain/piece/JangTest.java @@ -21,4 +21,16 @@ void destination_exception() { assertThatThrownBy(() -> jang.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } + + @Test + @DisplayName("장은 궁성 밖으로 나갈 수 없습니다.") + void can_not_move_outside_castle() { + Piece jang = new Jang(Team.CHO); + Point from = Point.of(3, 0); + Point to = Point.of(2, 0); + + assertThatThrownBy(() -> jang.getRoutePoints(from, to)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 장은 궁성 밖으로 나갈 수 없습니다."); + } } diff --git a/src/test/java/janggi/domain/piece/SaTest.java b/src/test/java/janggi/domain/piece/SaTest.java index de21623269..d78bd54484 100644 --- a/src/test/java/janggi/domain/piece/SaTest.java +++ b/src/test/java/janggi/domain/piece/SaTest.java @@ -21,4 +21,16 @@ void destination_exception() { assertThatThrownBy(() -> sa.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } + + @Test + @DisplayName("사는 궁성 밖으로 나갈 수 없습니다.") + void can_not_move_outside_castle() { + Piece sa = new Sa(Team.CHO); + Point from = Point.of(3, 0); + Point to = Point.of(2, 0); + + assertThatThrownBy(() -> sa.getRoutePoints(from, to)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 사는 궁성 밖으로 나갈 수 없습니다."); + } } From e36b69fcbc85b56c61de7e2db008388a4280cab1 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:03:30 +0900 Subject: [PATCH 020/110] =?UTF-8?q?feat(jang&sa):=20=EA=B6=81=EC=84=B1=20?= =?UTF-8?q?=EB=B0=96=EC=9C=BC=EB=A1=9C=20=EB=AA=BB=EB=82=98=EA=B0=90=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Jang.java | 3 +++ src/main/java/janggi/domain/piece/Sa.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index 50d105f30d..e43bb8af65 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -18,6 +18,9 @@ public Jang(Team team) { @Override public Points getRoutePoints(Point from, Point to) { + if (!from.inSameCastle(to)) { + throw new IllegalArgumentException("[ERROR] 장은 궁성 밖으로 나갈 수 없습니다."); + } int pathCol = to.calculatePathColumn(from); int pathRow = to.calculatePathRow(from); int distanceCol = abs(pathCol); diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index bc3b1f39e0..88f735542b 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -18,6 +18,9 @@ public Sa(Team team) { @Override public Points getRoutePoints(Point from, Point to) { + if (!from.inSameCastle(to)) { + throw new IllegalArgumentException("[ERROR] 사는 궁성 밖으로 나갈 수 없습니다."); + } int pathCol = to.calculatePathColumn(from); int pathRow = to.calculatePathRow(from); int distanceCol = abs(pathCol); From b200d507211db534b138d2e1db3b0ed07e871ea4 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:18:48 +0900 Subject: [PATCH 021/110] =?UTF-8?q?test(jol):=20=EA=B6=81=EC=84=B1?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=95=9C=EB=82=98=EB=9D=BC=20=EC=A1=B8?= =?UTF-8?q?=EC=9D=80=20=EC=9C=84=EB=A1=9C=20=EB=AA=BB=EA=B0=80=EB=8A=94=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/piece/JolTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/janggi/domain/piece/JolTest.java b/src/test/java/janggi/domain/piece/JolTest.java index 8edc094497..501b15fe3c 100644 --- a/src/test/java/janggi/domain/piece/JolTest.java +++ b/src/test/java/janggi/domain/piece/JolTest.java @@ -1,11 +1,14 @@ package janggi.domain.piece; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class JolTest { @@ -47,4 +50,34 @@ void destination_exception() { assertThatThrownBy(() -> jol.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class); } + + @Test + @DisplayName("궁성 안에서는 대각선으로 이동 할 수 있다.") + void can_move_diagonal() { + Piece jol = new Jol(Team.HAN); + Point from = Point.of(5, 2); + Point to = Point.of(4, 1); + assertThat(jol.getRoutePoints(from, to) + .getPoints() + .getFirst() + .getColumn() + ).isEqualTo(4); + assertThat(jol.getRoutePoints(from, to) + .getPoints() + .getFirst() + .getRow() + ).isEqualTo(1); + } + + @ParameterizedTest + @DisplayName("궁성 안에서 한나라는 위로 대각선은 못간다.") + @CsvSource(value = {"4:1:5:2", "4:1:3:2"}, delimiter = ':') + void can_not_move_to_up_diagonal(int fromColumn, int fromRow, int toColumn, int toRow) { + Piece jol = new Jol(Team.HAN); + Point from = Point.of(fromColumn, fromRow); + Point to = Point.of(toColumn, toRow); + assertThatThrownBy(() -> jol.getRoutePoints(from, to)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } } From 4cddc93c792563a4bb56952c72f52fb2f7c8bf78 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:19:10 +0900 Subject: [PATCH 022/110] =?UTF-8?q?feat(jol):=20=EA=B6=81=EC=84=B1?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=8C=80=EA=B0=81=EC=84=A0=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Jol.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index d7cb203f40..3f79fb6602 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; @@ -20,14 +21,21 @@ public Jol(Team team) { public Points getRoutePoints(Point from, Point to) { int pathCol = to.calculatePathColumn(from); int pathRow = to.calculatePathRow(from); + int signCol = Integer.compare(pathCol, 0); int signRow = Integer.compare(pathRow, 0); int distanceCol = abs(pathCol); int distanceRow = abs(pathRow); - if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol + distanceRow > MAX_DISTANCE)) { + if ((super.getTeam().equals(Team.CHO) && signRow < 0) || (super.getTeam().equals(Team.HAN) && signRow > 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - if ((super.getTeam().equals(Team.CHO) && signRow < 0) || (super.getTeam().equals(Team.HAN) && signRow > 0)) { + if (from.inSameCastle(to)) { + CastleDirection direction = CastleDirection.find(from, signCol, signRow); + Point point = Point.of(from.getColumn() + direction.getTargetCol(), + from.getRow() + direction.getTargetRow()); + return new Points(List.of(point)); + } + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol + distanceRow > MAX_DISTANCE)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } return new Points(List.of(to)); From ac477054d23098dfb651823801e02d13901c2c8d Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:30:14 +0900 Subject: [PATCH 023/110] =?UTF-8?q?refactor(jang&sa):=20=EB=8C=80=EA=B0=81?= =?UTF-8?q?=EC=84=A0=20=EB=B0=A9=ED=96=A5=20=EC=A0=9C=ED=95=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Jang.java | 5 ++++- src/main/java/janggi/domain/piece/Sa.java | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index e43bb8af65..bb0502f178 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; @@ -29,7 +30,9 @@ public Points getRoutePoints(Point from, Point to) { if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return new Points(List.of(to)); + CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); + Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); + return new Points(List.of(point)); } @Override diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index 88f735542b..59560477e3 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; @@ -29,7 +30,9 @@ public Points getRoutePoints(Point from, Point to) { if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } - return new Points(List.of(to)); + CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); + Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); + return new Points(List.of(point)); } @Override From 27b3b6ea54e3667f85389eb5e0d087bce46fd395 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:52:55 +0900 Subject: [PATCH 024/110] =?UTF-8?q?refactor(Cha&Pho):=20=EB=8C=80=EA=B0=81?= =?UTF-8?q?=EC=84=A0=20=EB=B0=A9=ED=96=A5=20=EC=A0=9C=ED=95=9C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cha.java | 29 ++++++++++++---------- src/main/java/janggi/domain/piece/Pho.java | 29 ++++++++++++---------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index 301cc0cd98..a6c07e6163 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -21,20 +21,12 @@ public Points getRoutePoints(Point from, Point to) { int pathRow = to.calculatePathRow(from); int signCol = Integer.compare(pathCol, 0); int signRow = Integer.compare(pathRow, 0); - List points = new ArrayList<>(); - if (from.inSameCastle(to)) { - CastleDirection castleDirection = CastleDirection.find(from, signCol, signRow); - points.add(Point.of( - from.getColumn() + castleDirection.getTargetCol(), - from.getRow() + castleDirection.getTargetRow() - ) - ); - return new Points(points); - } - if (pathRow != 0 && pathCol != 0) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } + + validateDirection(from, to, signCol, signRow, pathCol, pathRow); + int distance = Math.max(abs(pathCol), abs(pathRow)); + + List points = new ArrayList<>(); for (int i = 1; i < distance; i++) { int nextCol = from.getColumn() + (signCol * i); int nextRow = from.getRow() + (signRow * i); @@ -42,4 +34,15 @@ public Points getRoutePoints(Point from, Point to) { } return new Points(points); } + + private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { + if (from.inSameCastle(to)) { + CastleDirection.find(from, signCol, signRow); + return; + } + + if (pathCol != 0 && pathRow !=0) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } } diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index a200596077..ca489fd5aa 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -22,20 +22,12 @@ public Points getRoutePoints(Point from, Point to) { int pathRow = to.calculatePathRow(from); int signCol = Integer.compare(pathCol, 0); int signRow = Integer.compare(pathRow, 0); - List points = new ArrayList<>(); - if (from.inSameCastle(to)) { - CastleDirection castleDirection = CastleDirection.find(from, signCol, signRow); - points.add(Point.of( - from.getColumn() + castleDirection.getTargetCol(), - from.getRow() + castleDirection.getTargetRow() - ) - ); - return new Points(points); - } - if (pathRow != 0 && pathCol != 0) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } + + validateDirection(from, to, signCol, signRow, pathCol, pathRow); + int distance = Math.max(abs(pathCol), abs(pathRow)); + + List points = new ArrayList<>(); for (int i = 1; i < distance; i++) { int nextCol = from.getColumn() + (signCol * i); int nextRow = from.getRow() + (signRow * i); @@ -56,4 +48,15 @@ public boolean canMove(Route route) { public boolean canCapture(Piece target) { return !target.isSameType(PieceType.PHO); } + + private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { + if (from.inSameCastle(to)) { + CastleDirection.find(from, signCol, signRow); + return; + } + + if (pathCol != 0 && pathRow !=0) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } } From 3b1797bef6685d830ad154e9f4d815bb02098b74 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 16:53:09 +0900 Subject: [PATCH 025/110] =?UTF-8?q?refactor(Point):=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/point/Point.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/janggi/domain/point/Point.java b/src/main/java/janggi/domain/point/Point.java index 79b78d7adf..89dc1a81a9 100644 --- a/src/main/java/janggi/domain/point/Point.java +++ b/src/main/java/janggi/domain/point/Point.java @@ -9,6 +9,12 @@ public class Point { private static final List> CACHE; private static final int ROW_RANGE = 10; private static final int COLUMN_RANGE = 9; + private static final int HAN_CASTLE_ZONE_ROW_MIN = 7; + private static final int HAN_CASTLE_ZONE_ROW_MAX = 9; + private static final int CHO_CASTLE_ZONE_ROW_MIN =0; + private static final int CHO_CASTLE_ZONE_ROW_MAX =2; + private static final int CASTLE_ZONE_COLUMN_MIN = 3; + private static final int CASTLE_ZONE_COLUMN_MAX = 5; private final int col; private final int row; @@ -45,7 +51,7 @@ public int calculatePathRow(Point from) { public boolean inSameCastle(Point other) { if (this.isCastle() && other.isCastle()) { - return (this.row <= 2) == (other.row <= 2); + return (this.row <= CHO_CASTLE_ZONE_ROW_MAX) == (other.row <= CHO_CASTLE_ZONE_ROW_MAX); } return false; } @@ -65,9 +71,9 @@ private static void addColumn(List row, int col) { } private boolean isCastle() { - boolean isColumnCastle = col >= 3 && col <= 5; - boolean isRowTopCastle = row >= 7 && row <= 9; - boolean isRowBottomCastle = row <= 2 && row >= 0; - return isColumnCastle && (isRowTopCastle || isRowBottomCastle); + boolean isColumnCastle = col >= CASTLE_ZONE_COLUMN_MIN && col <= CASTLE_ZONE_COLUMN_MAX; + boolean isRowHanCastle = row >= HAN_CASTLE_ZONE_ROW_MIN && row <= HAN_CASTLE_ZONE_ROW_MAX; + boolean isRowChoCastle = row <= CHO_CASTLE_ZONE_ROW_MAX && row >= CHO_CASTLE_ZONE_ROW_MIN; + return isColumnCastle && (isRowHanCastle || isRowChoCastle); } } From 1dccc84d39d3d213b5d499e5e096a40825dd9d22 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Mon, 30 Mar 2026 17:03:50 +0900 Subject: [PATCH 026/110] =?UTF-8?q?refactor(Piece):=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=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/Jang.java | 11 +++++++---- src/main/java/janggi/domain/piece/Jol.java | 21 ++++++++++++++------- src/main/java/janggi/domain/piece/Sa.java | 11 +++++++---- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index bb0502f178..2499172e66 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -26,10 +26,7 @@ public Points getRoutePoints(Point from, Point to) { int pathRow = to.calculatePathRow(from); int distanceCol = abs(pathCol); int distanceRow = abs(pathRow); - - if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } + validateDistance(distanceCol, distanceRow); CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); return new Points(List.of(point)); @@ -39,4 +36,10 @@ public Points getRoutePoints(Point from, Point to) { public boolean canMove(Route route) { return !route.hasAlly(super.getTeam()); } + + private void validateDistance(int distanceCol, int distanceRow) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } } diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index 3f79fb6602..e008f78909 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -23,21 +23,16 @@ public Points getRoutePoints(Point from, Point to) { int pathRow = to.calculatePathRow(from); int signCol = Integer.compare(pathCol, 0); int signRow = Integer.compare(pathRow, 0); + validateForward(signRow); int distanceCol = abs(pathCol); int distanceRow = abs(pathRow); - - if ((super.getTeam().equals(Team.CHO) && signRow < 0) || (super.getTeam().equals(Team.HAN) && signRow > 0)) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } if (from.inSameCastle(to)) { CastleDirection direction = CastleDirection.find(from, signCol, signRow); Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); return new Points(List.of(point)); } - if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol + distanceRow > MAX_DISTANCE)) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } + validateDistance(distanceCol, distanceRow); return new Points(List.of(to)); } @@ -45,4 +40,16 @@ public Points getRoutePoints(Point from, Point to) { public boolean canMove(Route route) { return !route.hasAlly(super.getTeam()); } + + private void validateForward(int signRow) { + if ((super.getTeam().equals(Team.CHO) && signRow < 0) || (super.getTeam().equals(Team.HAN) && signRow > 0)) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } + + private void validateDistance(int distanceCol, int distanceRow) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol + distanceRow > MAX_DISTANCE)) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } } diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index 59560477e3..cba296831c 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -26,10 +26,7 @@ public Points getRoutePoints(Point from, Point to) { int pathRow = to.calculatePathRow(from); int distanceCol = abs(pathCol); int distanceRow = abs(pathRow); - - if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } + validateDistance(distanceCol, distanceRow); CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); return new Points(List.of(point)); @@ -39,4 +36,10 @@ public Points getRoutePoints(Point from, Point to) { public boolean canMove(Route route) { return !route.hasAlly(super.getTeam()); } + + private void validateDistance(int distanceCol, int distanceRow) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } } From 2d06433e5d4697f68f95a05555645495343a8d98 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 18:00:46 +0900 Subject: [PATCH 027/110] =?UTF-8?q?chore(Database):=20h2,=20jdbc=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index ce846f70cc..6501102378 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ repositories { } dependencies { + implementation 'com.h2database:h2:2.2.224' testImplementation platform('org.junit:junit-bom:5.11.4') testImplementation platform('org.assertj:assertj-bom:3.27.3') testImplementation('org.junit.jupiter:junit-jupiter') From 80ea3f10028b5b2f8295c6e602e37d4bca2f13db Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 18:02:56 +0900 Subject: [PATCH 028/110] =?UTF-8?q?chore(Board):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/{ => board}/Board.java | 2 +- src/main/java/janggi/domain/status/ChoTurn.java | 2 +- src/main/java/janggi/domain/status/FinishedGame.java | 2 +- src/main/java/janggi/domain/status/GameStatus.java | 2 +- src/main/java/janggi/domain/status/HanTurn.java | 2 +- src/test/java/janggi/domain/BoardTest.java | 1 + src/test/java/janggi/domain/piece/PhoTest.java | 2 +- src/test/java/janggi/domain/status/HanTurnTest.java | 2 +- 8 files changed, 8 insertions(+), 7 deletions(-) rename src/main/java/janggi/domain/{ => board}/Board.java (99%) diff --git a/src/main/java/janggi/domain/Board.java b/src/main/java/janggi/domain/board/Board.java similarity index 99% rename from src/main/java/janggi/domain/Board.java rename to src/main/java/janggi/domain/board/Board.java index 359f696657..7025d69288 100644 --- a/src/main/java/janggi/domain/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -1,4 +1,4 @@ -package janggi.domain; +package janggi.domain.board; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; diff --git a/src/main/java/janggi/domain/status/ChoTurn.java b/src/main/java/janggi/domain/status/ChoTurn.java index 2dbc49c1d1..0c32c2850a 100644 --- a/src/main/java/janggi/domain/status/ChoTurn.java +++ b/src/main/java/janggi/domain/status/ChoTurn.java @@ -1,6 +1,6 @@ package janggi.domain.status; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; public class ChoTurn implements GameStatus { diff --git a/src/main/java/janggi/domain/status/FinishedGame.java b/src/main/java/janggi/domain/status/FinishedGame.java index b482446a62..06addb97b4 100644 --- a/src/main/java/janggi/domain/status/FinishedGame.java +++ b/src/main/java/janggi/domain/status/FinishedGame.java @@ -1,6 +1,6 @@ package janggi.domain.status; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; public class FinishedGame implements GameStatus { diff --git a/src/main/java/janggi/domain/status/GameStatus.java b/src/main/java/janggi/domain/status/GameStatus.java index e8337d6e18..36a8731200 100644 --- a/src/main/java/janggi/domain/status/GameStatus.java +++ b/src/main/java/janggi/domain/status/GameStatus.java @@ -1,6 +1,6 @@ package janggi.domain.status; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; public interface GameStatus { diff --git a/src/main/java/janggi/domain/status/HanTurn.java b/src/main/java/janggi/domain/status/HanTurn.java index 56da0ca700..a0c510538e 100644 --- a/src/main/java/janggi/domain/status/HanTurn.java +++ b/src/main/java/janggi/domain/status/HanTurn.java @@ -1,6 +1,6 @@ package janggi.domain.status; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; public class HanTurn implements GameStatus { diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 5a1c1d5151..8066d06047 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -1,5 +1,6 @@ package janggi.domain; +import janggi.domain.board.Board; import janggi.domain.piece.Cha; import janggi.domain.piece.Jol; import janggi.domain.piece.Ma; diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index adde68d717..833756e074 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; diff --git a/src/test/java/janggi/domain/status/HanTurnTest.java b/src/test/java/janggi/domain/status/HanTurnTest.java index d54c33f588..4e2358bf30 100644 --- a/src/test/java/janggi/domain/status/HanTurnTest.java +++ b/src/test/java/janggi/domain/status/HanTurnTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; import janggi.domain.piece.Cha; import janggi.domain.piece.Jang; From 331725b784424962f7fb84d8ff68f1b1dc6bba23 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 18:03:16 +0900 Subject: [PATCH 029/110] =?UTF-8?q?chore(Board):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/status/ChoTurnTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/janggi/domain/status/ChoTurnTest.java b/src/test/java/janggi/domain/status/ChoTurnTest.java index d815472225..56d3795287 100644 --- a/src/test/java/janggi/domain/status/ChoTurnTest.java +++ b/src/test/java/janggi/domain/status/ChoTurnTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import janggi.domain.Board; +import janggi.domain.board.Board; import janggi.domain.point.Point; import janggi.domain.piece.Cha; import janggi.domain.piece.Jang; From 15aed38bf09bca7bfcacdd0539b45c6d83489327 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 18:03:44 +0900 Subject: [PATCH 030/110] =?UTF-8?q?style(Cha):=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cha.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index a6c07e6163..8bcceed1e7 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -40,7 +40,6 @@ private void validateDirection(Point from, Point to, int signCol, int signRow, i CastleDirection.find(from, signCol, signRow); return; } - if (pathCol != 0 && pathRow !=0) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } From 0b1339762e76f495f37686fa030c23102e64b21c Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 18:04:50 +0900 Subject: [PATCH 031/110] =?UTF-8?q?test(Board):=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/BoardTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/BoardTest.java index 8066d06047..15712cbbcb 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/BoardTest.java @@ -88,6 +88,4 @@ void can_move_pho_diagonal() { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 이동할 수 없는 방향입니다."); } - - } From 385688804486c0eee36424fcf1148e9399892846 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:00:23 +0900 Subject: [PATCH 032/110] =?UTF-8?q?test(Board):=20=EB=82=98=EB=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=90=EC=88=98=20=EA=B3=84=EC=82=B0=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/{ => board}/BoardTest.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) rename src/test/java/janggi/domain/{ => board}/BoardTest.java (82%) diff --git a/src/test/java/janggi/domain/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java similarity index 82% rename from src/test/java/janggi/domain/BoardTest.java rename to src/test/java/janggi/domain/board/BoardTest.java index 15712cbbcb..c87d855eea 100644 --- a/src/test/java/janggi/domain/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -1,6 +1,5 @@ -package janggi.domain; +package janggi.domain.board; -import janggi.domain.board.Board; import janggi.domain.piece.Cha; import janggi.domain.piece.Jol; import janggi.domain.piece.Ma; @@ -88,4 +87,24 @@ void can_move_pho_diagonal() { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 이동할 수 없는 방향입니다."); } + + @Test + @DisplayName("한나라의 기물이 차와 포만 있으면 총합은 1.5점 가산점을 더해서 21.5이다.") + void han_total_score() { + Map pieces = new LinkedHashMap<>(); + pieces.put(Point.of(0, 0), new Cha(Team.HAN)); + pieces.put(Point.of(1, 1), new Pho(Team.HAN)); + board.init(pieces); + Assertions.assertThat(board.calculateScore(Team.HAN)).isEqualTo(21.5); + } + + @Test + @DisplayName("초나라의 기물이 차와 포만 있으면 총합은 20이다.") + void cho_total_score() { + Map pieces = new LinkedHashMap<>(); + pieces.put(Point.of(0, 0), new Cha(Team.CHO)); + pieces.put(Point.of(1, 1), new Pho(Team.CHO)); + board.init(pieces); + Assertions.assertThat(board.calculateScore(Team.CHO)).isEqualTo(20); + } } From 45b8feeedabcd8d9b43ba47c8c7e5d72a9e0c43c Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:02:40 +0900 Subject: [PATCH 033/110] =?UTF-8?q?feat(Board):=20=EB=82=98=EB=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=90=EC=88=98=20=EA=B3=84=EC=82=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/JanggiGame.java | 20 +++++++++++++++---- src/main/java/janggi/domain/board/Board.java | 14 ++++++++++++- .../janggi/domain/piece/AbstractPiece.java | 9 ++++++++- src/main/java/janggi/domain/piece/Cha.java | 4 +++- src/main/java/janggi/domain/piece/Jang.java | 2 +- src/main/java/janggi/domain/piece/Jol.java | 3 ++- src/main/java/janggi/domain/piece/Ma.java | 4 +++- src/main/java/janggi/domain/piece/Pho.java | 4 +++- src/main/java/janggi/domain/piece/Sa.java | 3 ++- src/main/java/janggi/domain/piece/Sang.java | 4 +++- 10 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/main/java/janggi/domain/JanggiGame.java b/src/main/java/janggi/domain/JanggiGame.java index d7553ef828..b16d3508c2 100644 --- a/src/main/java/janggi/domain/JanggiGame.java +++ b/src/main/java/janggi/domain/JanggiGame.java @@ -1,8 +1,8 @@ package janggi.domain; +import janggi.domain.board.Board; import janggi.domain.piece.Piece; import janggi.domain.point.Point; -import janggi.domain.status.ChoTurn; import janggi.domain.status.GameStatus; import janggi.domain.status.Team; import java.util.List; @@ -12,9 +12,9 @@ public class JanggiGame { private final Board board; private GameStatus gameStatus; - public JanggiGame(Board board) { + public JanggiGame(Board board, GameStatus gameStatus) { this.board = board; - this.gameStatus = new ChoTurn(); + this.gameStatus = gameStatus; } public boolean isFinished() { @@ -29,10 +29,22 @@ public Team getWinner() { } public List> getBoardStatus() { - return board.getPoints(); + return board.getPieces(); } public void play(Point from, Point to) { this.gameStatus = gameStatus.move(from, to, board); } + + public Team getTeam() { + return gameStatus.getTeam(); + } + + public double getChoScore() { + return board.calculateScore(Team.CHO); + } + + public double getHanScore() { + return board.calculateScore(Team.HAN); + } } diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 7025d69288..c86f1d696a 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -49,7 +49,7 @@ public boolean isKingDie() { .count() < 2; } - public List> getPoints() { + public List> getPieces() { return IntStream.range(0, BOARD_HEIGHT) .mapToObj(row -> IntStream.range(0, BOARD_WIDTH) .mapToObj(col -> Point.of(col, row)) @@ -58,6 +58,18 @@ public List> getPoints() { ).toList(); } + public double calculateScore(Team team) { + int sum = pieces.values() + .stream() + .filter(piece -> piece.isSameTeam(team)) + .mapToInt(Piece::getScore) + .sum(); + if (team.equals(Team.HAN)) { + return sum + 1.5; + } + return sum; + } + public Route getRoute(Points points) { return new Route(points.getPoints().stream() .map(pieces::get) diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java index c554d74041..41289d30fd 100644 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -9,8 +9,10 @@ abstract class AbstractPiece implements Piece { private final Team team; private final PieceType type; + private final int score; - public AbstractPiece(Team team, PieceType type) { + public AbstractPiece(int score, Team team, PieceType type) { + this.score = score; this.team = team; this.type = type; } @@ -43,6 +45,11 @@ public PieceType getType() { return type; } + @Override + public int getScore() { + return score; + } + protected Team getTeam() { return this.team; } diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index 8bcceed1e7..9e82e1b4ba 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -11,8 +11,10 @@ public class Cha extends AbstractPiece { + private static final int SCORE = 13; + public Cha(Team team) { - super(team, PieceType.CHA); + super(SCORE, team, PieceType.CHA); } @Override diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index 2499172e66..8e9acbc800 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -14,7 +14,7 @@ public class Jang extends AbstractPiece { private static final int MAX_DISTANCE = 1; public Jang(Team team) { - super(team, PieceType.JANG); + super(0, team, PieceType.JANG); } @Override diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index e008f78909..15f65115b6 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -11,10 +11,11 @@ public class Jol extends AbstractPiece { + private static final int SCORE = 2; private static final int MAX_DISTANCE = 1; public Jol(Team team) { - super(team, PieceType.JOL); + super(SCORE, team, PieceType.JOL); } @Override diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index 96500cb168..5e0d299ae4 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -8,8 +8,10 @@ public class Ma extends AbstractPiece { + private static final int SCORE = 5; + public Ma(Team team) { - super(team, PieceType.MA); + super(SCORE, team, PieceType.MA); } @Override diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index ca489fd5aa..02beaa9935 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -12,8 +12,10 @@ public class Pho extends AbstractPiece { + private static final int SCORE = 7; + public Pho(Team team) { - super(team, PieceType.PHO); + super(SCORE, team, PieceType.PHO); } @Override diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index cba296831c..4a1987b9f6 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -11,10 +11,11 @@ public class Sa extends AbstractPiece { + private static final int SCORE = 3; private static final int MAX_DISTANCE = 1; public Sa(Team team) { - super(team, PieceType.SA); + super(SCORE, team, PieceType.SA); } @Override diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index 54f30f1c35..ed552ad4ca 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -8,8 +8,10 @@ public class Sang extends AbstractPiece { + private static final int SCORE = 3; + public Sang(Team team) { - super(team, PieceType.SANG); + super(SCORE, team, PieceType.SANG); } @Override From acaf869bea8fe86f357ec61099d8364dafbd36e8 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:03:03 +0900 Subject: [PATCH 034/110] =?UTF-8?q?feat(Board):=20=EB=82=98=EB=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=90=EC=88=98=20=EA=B3=84=EC=82=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Piece.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index e3b75caa95..cd2d33fc55 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -6,10 +6,11 @@ import janggi.domain.status.Team; public interface Piece { - Points getRoutePoints(Point from, Point to); - PieceType getType(); boolean canMove(Route route); boolean isSameTeam(Team team); boolean isSameType(PieceType type); boolean canCapture(Piece target); + Points getRoutePoints(Point from, Point to); + PieceType getType(); + int getScore(); } From 96e2d3bf9300128b27e4fe757b035bbc838b5754 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:03:29 +0900 Subject: [PATCH 035/110] =?UTF-8?q?chore(Point):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95=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/{ => point}/PointTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename src/test/java/janggi/domain/{ => point}/PointTest.java (89%) diff --git a/src/test/java/janggi/domain/PointTest.java b/src/test/java/janggi/domain/point/PointTest.java similarity index 89% rename from src/test/java/janggi/domain/PointTest.java rename to src/test/java/janggi/domain/point/PointTest.java index a1ac8654c4..c18b3b85d9 100644 --- a/src/test/java/janggi/domain/PointTest.java +++ b/src/test/java/janggi/domain/point/PointTest.java @@ -1,8 +1,7 @@ -package janggi.domain; +package janggi.domain.point; import static org.assertj.core.api.Assertions.assertThat; -import janggi.domain.point.Point; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From 910b99c13d3ee705716c55e0870e3732bb141a35 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:04:56 +0900 Subject: [PATCH 036/110] =?UTF-8?q?feat(JanggiRepository):=20=EC=9E=A5?= =?UTF-8?q?=EA=B8=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20DB=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/board/BoardRepository.java | 10 ++ .../domain/status/GameStatusFactory.java | 20 +++ .../janggi/infra/JdbcBoardRepository.java | 143 ++++++++++++++++++ .../java/janggi/infra/dao/GameRoomDao.java | 54 +++++++ src/main/java/janggi/infra/dao/PiecesDao.java | 66 ++++++++ .../java/janggi/infra/dto/GameRoomData.java | 27 ++++ src/main/java/janggi/infra/dto/PieceData.java | 9 ++ 7 files changed, 329 insertions(+) create mode 100644 src/main/java/janggi/domain/board/BoardRepository.java create mode 100644 src/main/java/janggi/domain/status/GameStatusFactory.java create mode 100644 src/main/java/janggi/infra/JdbcBoardRepository.java create mode 100644 src/main/java/janggi/infra/dao/GameRoomDao.java create mode 100644 src/main/java/janggi/infra/dao/PiecesDao.java create mode 100644 src/main/java/janggi/infra/dto/GameRoomData.java create mode 100644 src/main/java/janggi/infra/dto/PieceData.java diff --git a/src/main/java/janggi/domain/board/BoardRepository.java b/src/main/java/janggi/domain/board/BoardRepository.java new file mode 100644 index 0000000000..9d15a743d1 --- /dev/null +++ b/src/main/java/janggi/domain/board/BoardRepository.java @@ -0,0 +1,10 @@ +package janggi.domain.board; + +import janggi.domain.JanggiGame; +import janggi.domain.point.Point; + +public interface BoardRepository { + Long save(JanggiGame game); + void update(Long roomId, Point from, Point to, JanggiGame game); + JanggiGame loadGame(Long gameRoomId); +} diff --git a/src/main/java/janggi/domain/status/GameStatusFactory.java b/src/main/java/janggi/domain/status/GameStatusFactory.java new file mode 100644 index 0000000000..0297c56fad --- /dev/null +++ b/src/main/java/janggi/domain/status/GameStatusFactory.java @@ -0,0 +1,20 @@ +package janggi.domain.status; + +import java.util.Map; +import java.util.function.Supplier; + +public class GameStatusFactory { + + private static final Map> FACTORY = Map.of( + Team.CHO, ChoTurn::new, + Team.HAN, HanTurn::new + ); + + public static GameStatus create(Team team) { + Supplier supplier = FACTORY.get(team); + if (supplier == null) { + throw new IllegalArgumentException("[ERROR] 존재하지 않는 팀입니다."); + } + return supplier.get(); + } +} diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java new file mode 100644 index 0000000000..598b4324f9 --- /dev/null +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -0,0 +1,143 @@ +package janggi.infra; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardRepository; +import janggi.domain.JanggiGame; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceFactory; +import janggi.domain.piece.PieceType; +import janggi.domain.point.Point; +import janggi.domain.status.GameStatusFactory; +import janggi.domain.status.Team; +import janggi.infra.dao.GameRoomDao; +import janggi.infra.dao.PiecesDao; +import janggi.infra.dto.GameRoomData; +import janggi.infra.dto.PieceData; +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +public class JdbcBoardRepository implements BoardRepository { + + private final GameRoomDao roomDao = new GameRoomDao(); + private final PiecesDao piecesDao = new PiecesDao(); + private final String url; + private final String username; + private final String password; + + public JdbcBoardRepository() { + try { + Properties properties = new Properties(); + InputStream inputStream = getClass().getClassLoader().getResourceAsStream("application.properties"); + properties.load(inputStream); + url = properties.getProperty("db.url"); + username = properties.getProperty("db.username"); + password = properties.getProperty("db.password"); + initTable(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public Long save(JanggiGame game) { + try(Connection connection = getConnection()) { + Long roomId = roomDao.save(GameRoomData.from(game), connection); + List> pieces = game.getBoardStatus(); + List data = new ArrayList<>(); + for (int i = 0; i < pieces.size(); i++) { + addPieceData(pieces, i, data); + } + piecesDao.save(roomId, data, connection); + return roomId; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public void update(Long roomId, Point from, Point to, JanggiGame game) { + try(Connection connection = getConnection()) { + roomDao.update(roomId, GameRoomData.from(game), connection); + piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); + piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public JanggiGame loadGame(Long gameRoomId) { + try(Connection connection = getConnection()) { + GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection); + List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); + Map pieces = new LinkedHashMap<>(); + pieceDatas.forEach(pieceData -> { + PieceType type = PieceType.valueOf(pieceData.pieceName()); + Team team = Team.valueOf(pieceData.teamName()); + Point point = Point.of(pieceData.col(), pieceData.row()); + Piece piece = PieceFactory.createPiece(team, type); + pieces.put(point, piece); + }); + Board board = new Board(); + board.init(pieces); + return new JanggiGame(board, GameStatusFactory.create(Team.valueOf(roomData.currentTurn()))); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private Connection getConnection() throws SQLException { + return DriverManager.getConnection(url, username, password); + } + + private void initTable() { + String createGameRoom = """ + CREATE TABLE IF NOT EXISTS game_room( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + current_turn VARCHAR(10) NOT NULL, + winner VARCHAR(10), + cha_score DOUBLE, + han_score DOUBLE + ) + """; + + String createPiece = """ + CREATE TABLE IF NOT EXISTS piece( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + game_room_id BIGINT NOT NULL, + piece_name VARCHAR(10) NOT NULL, + team VARCHAR(10) NOT NULL, + row_pos INT NOT NULL, + col_pos INT NOT NULL, + FOREIGN KEY (game_room_id) REFERENCES game_room(id) ON DELETE CASCADE + ) + """; + try(Connection connection = getConnection()) { + Statement statement = connection.createStatement(); + statement.execute(createGameRoom); + statement.execute(createPiece); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void addPieceData(List> pieces, int i, List data) { + for (int j = 0; j < pieces.get(i).size(); j++) { + Piece piece = pieces.get(i).get(j); + if (piece == null) { + continue; + } + data.add(new PieceData(piece.getType().name(), + piece.isSameTeam(Team.HAN) ? Team.HAN.name() : Team.CHO.name(), i, j)); + } + } +} diff --git a/src/main/java/janggi/infra/dao/GameRoomDao.java b/src/main/java/janggi/infra/dao/GameRoomDao.java new file mode 100644 index 0000000000..4e9297bf8c --- /dev/null +++ b/src/main/java/janggi/infra/dao/GameRoomDao.java @@ -0,0 +1,54 @@ +package janggi.infra.dao; + +import janggi.infra.dto.GameRoomData; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class GameRoomDao { + + public Long save(GameRoomData data, Connection connection) throws SQLException { + String sql = "INSERT INTO game_room (current_turn, winner, cha_score, han_score) VALUES (?, ?, ?, ?)"; + PreparedStatement roomStatement = connection.prepareStatement(sql, + Statement.RETURN_GENERATED_KEYS); + roomStatement.setString(1, data.currentTurn()); + roomStatement.setString(2, data.winner()); + roomStatement.setDouble(3, data.choScore()); + roomStatement.setDouble(4, data.hanScore()); + roomStatement.executeUpdate(); + ResultSet resultSet = roomStatement.getGeneratedKeys(); + if (!resultSet.next()) { + throw new SQLException("[ERROR] 게임 보드 생성 실패"); + } + return resultSet.getLong(1); + } + + public void update(Long roomId, GameRoomData data, Connection connection) throws SQLException { + String sql = "UPDATE game_room SET current_turn = ?, winner = ?, cha_score = ?, han_score = ? WHERE id = ?"; + PreparedStatement roomStatement = connection.prepareStatement(sql); + roomStatement.setString(1, data.currentTurn()); + roomStatement.setString(2, data.winner()); + roomStatement.setDouble(3, data.choScore()); + roomStatement.setDouble(4, data.hanScore()); + roomStatement.setLong(5, roomId); + roomStatement.executeUpdate(); + } + + public GameRoomData findRoomById(Long roomId, Connection connection) throws SQLException { + String sql = "SELECT current_turn, winner, cha_score, han_score FROM game_room WHERE id=?"; + PreparedStatement roomStatement = connection.prepareStatement(sql); + roomStatement.setLong(1, roomId); + ResultSet resultSet = roomStatement.executeQuery(); + if (resultSet.next()) { + return new GameRoomData( + resultSet.getString("current_turn"), + resultSet.getString("winner"), + resultSet.getDouble("cha_score"), + resultSet.getDouble("han_score") + ); + } + throw new IllegalArgumentException("[ERROR] 해당 방이 존재하지 않습니다."); + } +} diff --git a/src/main/java/janggi/infra/dao/PiecesDao.java b/src/main/java/janggi/infra/dao/PiecesDao.java new file mode 100644 index 0000000000..6e7ca4c14f --- /dev/null +++ b/src/main/java/janggi/infra/dao/PiecesDao.java @@ -0,0 +1,66 @@ +package janggi.infra.dao; + +import janggi.infra.dto.PieceData; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class PiecesDao { + + public void save(Long roomId, List data, Connection connection) throws SQLException { + String sql = "INSERT INTO piece (game_room_id, piece_name, team, row_pos, col_pos) VALUES (?, ?, ?, ?, ?)"; + PreparedStatement pieceStatement = connection.prepareStatement(sql); + for (PieceData piece : data) { + pieceStatement.setLong(1, roomId); + pieceStatement.setString(2, piece.pieceName()); + pieceStatement.setString(3, piece.teamName()); + pieceStatement.setInt(4, piece.row()); + pieceStatement.setInt(5, piece.col()); + pieceStatement.executeUpdate(); + } + } + + public void delete(Long roomId, int row, int col, Connection connection) throws SQLException { + String sql = "DELETE FROM piece WHERE game_room_id = ? AND row_pos = ? AND col_pos = ?"; + PreparedStatement killStatement = connection.prepareStatement(sql); + killStatement.setLong(1, roomId); + killStatement.setInt(2, row); + killStatement.setInt(3, col); + killStatement.executeUpdate(); + } + + public void update(Long roomId, int fromRow, int fromCol, int toRow, int toCol, Connection connection) throws SQLException { + String movePieceSql = "UPDATE piece SET row_pos = ?, col_pos = ? WHERE game_room_id = ? AND row_pos = ? AND col_pos = ?"; + PreparedStatement moveStatement = connection.prepareStatement(movePieceSql); + moveStatement.setInt(1, toRow); + moveStatement.setInt(2, toCol); + moveStatement.setLong(3, roomId); + moveStatement.setInt(4, fromRow); + moveStatement.setInt(5, fromCol); + moveStatement.executeUpdate(); + } + + public List findAllByRoomId(Long roomId, Connection connection) { + String sql = "SELECT piece_name, team, row_pos, col_pos FROM piece WHERE game_room_id = ?"; + List piecesData = new ArrayList<>(); + try { + PreparedStatement pieceStatement = connection.prepareStatement(sql); + pieceStatement.setLong(1, roomId); + ResultSet resultSet = pieceStatement.executeQuery(); + while (resultSet.next()) { + piecesData.add(new PieceData( + resultSet.getString("piece_name"), + resultSet.getString("team"), + resultSet.getInt("row_pos"), + resultSet.getInt("col_pos") + )); + } + return piecesData; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/janggi/infra/dto/GameRoomData.java b/src/main/java/janggi/infra/dto/GameRoomData.java new file mode 100644 index 0000000000..4ef77250fb --- /dev/null +++ b/src/main/java/janggi/infra/dto/GameRoomData.java @@ -0,0 +1,27 @@ +package janggi.infra.dto; + +import janggi.domain.JanggiGame; + +public record GameRoomData( + String currentTurn, + String winner, + double choScore, + double hanScore +) { + public static GameRoomData from(JanggiGame game) { + if (game.isFinished()) { + return new GameRoomData( + game.getTeam().name(), + game.getWinner().name(), + game.getChoScore(), + game.getHanScore() + ); + } + return new GameRoomData( + game.getTeam().name(), + null, + game.getChoScore(), + game.getHanScore() + ); + } +} diff --git a/src/main/java/janggi/infra/dto/PieceData.java b/src/main/java/janggi/infra/dto/PieceData.java new file mode 100644 index 0000000000..22c96a875c --- /dev/null +++ b/src/main/java/janggi/infra/dto/PieceData.java @@ -0,0 +1,9 @@ +package janggi.infra.dto; + +public record PieceData( + String pieceName, + String teamName, + int row, + int col +) { +} From ae7a073db87ee1061e4bec298f6da4c75c6dea05 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:05:45 +0900 Subject: [PATCH 037/110] =?UTF-8?q?feat(JanggiGameService):=20repository?= =?UTF-8?q?=EC=99=80=20domain=20=EA=B0=84=EC=9D=98=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=A0=80=EC=9E=A5=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?service=EB=8B=A8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/application/JanggiGameService.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/main/java/janggi/application/JanggiGameService.java diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java new file mode 100644 index 0000000000..c167203676 --- /dev/null +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -0,0 +1,57 @@ +package janggi.application; + +import janggi.domain.board.Board; +import janggi.domain.board.BoardRepository; +import janggi.domain.JanggiGame; +import janggi.domain.point.Point; +import janggi.domain.status.ChoTurn; +import janggi.domain.status.Team; +import janggi.presentation.dto.GameStatusInfo; + +public class JanggiGameService { + + private final BoardRepository repository; + private JanggiGame game; + + public JanggiGameService(BoardRepository repository) { + this.repository = repository; + } + + public Long startNewGame(Board initBoard) { + this.game = new JanggiGame(initBoard, new ChoTurn()); + return repository.save(this.game); + } + + public void loadExistsBoard(Long gameRoomId) { + this.game = repository.loadGame(gameRoomId); + } + + public GameStatusInfo getBoardStatus() { + return GameStatusInfo.from(game.getBoardStatus()); + } + + public boolean isFinished() { + return game.isFinished(); + } + + public void play(Long roomId, Point from, Point to) { + game.play(from, to); + repository.update(roomId, from, to, game); + } + + public Team winner() { + return game.getWinner(); + } + + public Team currentTurn() { + return game.getTeam(); + } + + public double getHanScore() { + return game.getHanScore(); + } + + public double getChoScore() { + return game.getChoScore(); + } +} From 0912c3644873335b217ea4e0adcdc8099249ae20 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:06:19 +0900 Subject: [PATCH 038/110] =?UTF-8?q?feat(JanggiGameController):=20Service?= =?UTF-8?q?=EB=8B=A8=EA=B3=BC=20View=EB=8B=A8=20=EA=B0=84=EC=9D=98=20?= =?UTF-8?q?=ED=98=91=EB=A0=A5=EC=9D=84=20=EC=9C=84=ED=95=9C=20Controller?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/JanggiGameController.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/janggi/presentation/JanggiGameController.java diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java new file mode 100644 index 0000000000..c64e738399 --- /dev/null +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -0,0 +1,67 @@ +package janggi.presentation; + +import janggi.application.JanggiGameService; +import janggi.domain.board.Board; +import janggi.domain.piece.Piece; +import janggi.domain.point.Point; +import janggi.domain.status.Team; +import janggi.presentation.dto.MoveCommand; +import janggi.presentation.dto.PositionInfo; +import janggi.presentation.ui.InputView; +import janggi.presentation.ui.OutputView; +import janggi.util.Console; +import janggi.util.FileParser; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class JanggiGameController { + + private final JanggiGameService service; + + public JanggiGameController(JanggiGameService service) { + this.service = service; + } + + public void run() { + Long roomId = chooseBoard(InputView.chooseNewGame()); + OutputView.printStartGame(); + OutputView.printGameStatus(service.getBoardStatus()); + OutputView.printCurrentScore(service.getHanScore(), service.getChoScore()); + while (!service.isFinished()) { + playGame(roomId); + } + OutputView.printWinner(service.winner()); + Console.close(); + } + + private void playGame(Long roomId) { + try { + Team team = service.currentTurn(); + MoveCommand points = InputView.readPoints(team); + service.play(roomId, points.from(), points.to()); + OutputView.printGameStatus(service.getBoardStatus()); + OutputView.printCurrentScore(service.getHanScore(), service.getChoScore()); + } catch (IllegalArgumentException e) { + OutputView.printError(e.getMessage()); + } + } + + private Long chooseBoard(String chosen) { + if (chosen.equals("n")) { + Long gameRoomId = InputView.chooseExistsGame(); + service.loadExistsBoard(gameRoomId); + return gameRoomId; + } + return service.startNewGame(readInitBoard()); + } + + private Board readInitBoard() { + Map pieces = new LinkedHashMap<>(); + List positionInfos = FileParser.readCsvFile("/janggi.csv"); + positionInfos.forEach(info -> pieces.put(info.point(), info.piece())); + Board board = new Board(); + board.init(pieces); + return board; + } +} From fcfd62a5d3af986e7b2f8fb04c32caad76623b63 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:06:39 +0900 Subject: [PATCH 039/110] =?UTF-8?q?feat(Application):=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 44 ++++++--------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index 59cc380d52..175f0f3142 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -1,37 +1,19 @@ package janggi; -import janggi.domain.Board; -import janggi.domain.JanggiGame; -import janggi.domain.point.Point; -import janggi.domain.piece.Piece; -import janggi.presentation.dto.GameStatusInfo; -import janggi.presentation.dto.MoveCommand; -import janggi.presentation.dto.PositionInfo; -import janggi.presentation.ui.InputView; -import janggi.presentation.ui.OutputView; -import janggi.util.Console; -import janggi.util.FileParser; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import janggi.application.JanggiGameService; +import janggi.domain.board.BoardRepository; +import janggi.infra.JdbcBoardRepository; +import janggi.presentation.JanggiGameController; +import java.sql.SQLException; +import org.h2.tools.Server; public class JanggiApplication { - public static void main(String[] args) { - List positionInfos = FileParser.readCsvFile("/janggi.csv"); - Map pieces = new LinkedHashMap<>(); - positionInfos.forEach(info -> pieces.put(info.point(), info.piece())); - Board board = new Board(); - board.init(pieces); - JanggiGame game = new JanggiGame(board); - - OutputView.printGameStatus(GameStatusInfo.from(game.getBoardStatus())); - OutputView.printStartGame(); - while (!game.isFinished()) { - MoveCommand points = InputView.readPoints(); - game.play(points.from(), points.to()); - OutputView.printGameStatus(GameStatusInfo.from(game.getBoardStatus())); - } - OutputView.printWinner(game.getWinner()); - Console.close(); + public static void main(String[] args) throws SQLException { + Server server = Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start(); + BoardRepository repository = new JdbcBoardRepository(); + JanggiGameService service = new JanggiGameService(repository); + JanggiGameController controller = new JanggiGameController(service); + controller.run(); + server.stop(); } } From 5e2e0d915a6c317bddbb600f075b176eaf60278f Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:07:37 +0900 Subject: [PATCH 040/110] =?UTF-8?q?feat(InputView):=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=20=EC=8B=9C=EC=9E=91=20=EB=B0=8F=20=EA=B2=8C=EC=9E=84=EB=B0=A9?= =?UTF-8?q?=20=EC=84=A0=ED=83=9D=20=EC=9E=85=EB=A0=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/presentation/ui/InputView.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/janggi/presentation/ui/InputView.java b/src/main/java/janggi/presentation/ui/InputView.java index f175fe2cf1..ef8f52c2e4 100644 --- a/src/main/java/janggi/presentation/ui/InputView.java +++ b/src/main/java/janggi/presentation/ui/InputView.java @@ -1,15 +1,33 @@ package janggi.presentation.ui; +import janggi.domain.status.Team; import janggi.presentation.dto.MoveCommand; import janggi.util.Console; import janggi.util.Parser; +import java.util.Map; public class InputView { + private static final Map DISPLAY_NAME = Map.of( + Team.HAN, "한", + Team.CHO, "초" + ); + private InputView() { } - public static MoveCommand readPoints() { + public static String chooseNewGame() { + System.out.println("새로운 장기 게임을 시작하시겠습니까?(y,n)"); + return Console.readLine(); + } + + public static Long chooseExistsGame() { + System.out.println("기존 장기 게임방ID를 입력해주세요."); + return Long.valueOf(Console.readLine()); + } + + public static MoveCommand readPoints(Team team) { + System.out.println("현재 " + DISPLAY_NAME.get(team) + "나라의 차례입니다."); return new MoveCommand(Parser.parsePoint(readFromPoint()), Parser.parsePoint(readToPoint()) ); From a6b33cf04843bf5fbb92163a02271bf31465ef8f Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:08:05 +0900 Subject: [PATCH 041/110] =?UTF-8?q?feat(OutputView):=20=EC=A0=90=EC=88=98?= =?UTF-8?q?=20=EB=B0=8F=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/presentation/ui/OutputView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/janggi/presentation/ui/OutputView.java b/src/main/java/janggi/presentation/ui/OutputView.java index 579750ac37..6001b3fe2d 100644 --- a/src/main/java/janggi/presentation/ui/OutputView.java +++ b/src/main/java/janggi/presentation/ui/OutputView.java @@ -20,7 +20,15 @@ public static void printGameStatus(GameStatusInfo status) { .forEach(System.out::println); } + public static void printCurrentScore(double hanScore, double choScore) { + System.out.printf("한 : %.1f, 초 : %.1f\n", hanScore, choScore); + } + public static void printStartGame() { System.out.println("장기 게임을 시작합니다. 초나라부터 시작하고, 왼쪽 아래를 (0,0)으로 합니다."); } + + public static void printError(String message) { + System.out.println(message); + } } From a3974b3ed468531e708836066ab6a1b33e720209 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:08:24 +0900 Subject: [PATCH 042/110] =?UTF-8?q?docs(readme):=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 77fda6504f..0b2f1aa156 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ - [X] 현재 위치와 이동할 위치 입력 안내 메시지 출력 (예: 1,1 1,2) - [X] 사용자 입력 받기 - [X] 입력값 앞뒤 공백 제거 +- [X] 사용자로부터 게임 선택 입력 받기 + - [X] 새로운 게임 선택 여부 입력받기(y,n) + - [X] n 입력시 기존 게임방 ID 입력받기 + ### 장기 게임 (JanggiGame) - [X] 장기 게임 흐름 관리 @@ -31,6 +35,7 @@ - [X] 기물(Piece)이 반환한 이동 경로 상에 다른 기물(장애물)이 있는지 최종 검증 (길막힘 판별) - [X] 검증 통과 시 보드 상태 업데이트 (기물 이동) - [X] 도착지에 적군 기물이 있다면 맵에서 제거 (포획 처리) +- [X] 현재 점수 계산 결과 반환 #### 기물 공통 (Piece - 움직임 전략 패턴) - [X] 기물의 소속 팀(한/초) 반환 @@ -51,8 +56,9 @@ ### 📤 출력 (OutputView) #### 게임 진행 상태 출력 - [X] 게임 시작 안내 메시지 출력 -- [ ] 매 턴마다 현재 누구의 턴인지 출력 +- [X] 매 턴마다 현재 누구의 턴인지 출력 - [X] 매 턴마다 이동 결과가 반영된 현재 장기판의 상태를 시각적으로 출력 +- [X] 매 턴마다 현재 점수 출력 #### 게임 종료 출력 - [X] 승리 팀 안내 및 게임 종료 메시지 출력 @@ -64,4 +70,4 @@ - 상마상마, 마상마상 등의 상차림 변경은 미구현 - 외통수 시 게임을 종료하는 기능 미구현(장을 잡을 때까지 게임 진행) - 궁성을 구현하지 않아서, 장, 사의 이동 범위 제한이 현재는 없음 -- 궁성 내부에서의 기물마다의 특수한 이동 경로 또한 현재는 없음 \ No newline at end of file +- 궁성 내부에서의 기물마다의 특수한 이동 경로 또한 현재는 없음 From 4432a08c968f5d50eca2a54a8388a6b01c01a768 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Tue, 31 Mar 2026 22:14:05 +0900 Subject: [PATCH 043/110] =?UTF-8?q?refactor(AbstractPiece):=20=EB=8B=A4?= =?UTF-8?q?=EC=A4=91=20=EC=83=81=EC=86=8D=20=EC=9A=94=EC=86=8C=EA=B0=80=20?= =?UTF-8?q?=EC=97=86=EC=96=B4,=20=EC=B6=94=EC=83=81=20=EA=B3=A8=EA=B2=A9?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/piece/AbstractPiece.java | 56 ------------------- src/main/java/janggi/domain/piece/Cha.java | 2 +- src/main/java/janggi/domain/piece/Jang.java | 2 +- src/main/java/janggi/domain/piece/Jol.java | 2 +- src/main/java/janggi/domain/piece/Ma.java | 2 +- src/main/java/janggi/domain/piece/Pho.java | 2 +- src/main/java/janggi/domain/piece/Piece.java | 49 +++++++++++++--- src/main/java/janggi/domain/piece/Sa.java | 2 +- src/main/java/janggi/domain/piece/Sang.java | 2 +- 9 files changed, 48 insertions(+), 71 deletions(-) delete mode 100644 src/main/java/janggi/domain/piece/AbstractPiece.java diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java deleted file mode 100644 index 41289d30fd..0000000000 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ /dev/null @@ -1,56 +0,0 @@ -package janggi.domain.piece; - -import janggi.domain.point.Point; -import janggi.domain.point.Points; -import janggi.domain.point.Route; -import janggi.domain.status.Team; - -abstract class AbstractPiece implements Piece { - - private final Team team; - private final PieceType type; - private final int score; - - public AbstractPiece(int score, Team team, PieceType type) { - this.score = score; - this.team = team; - this.type = type; - } - - @Override - public abstract Points getRoutePoints(Point from, Point to); - - @Override - public boolean canCapture(Piece target) { - return true; - } - - @Override - public boolean canMove(Route route) { - return route.isEmpty(); - } - - @Override - public boolean isSameTeam(Team team) { - return this.team.equals(team); - } - - @Override - public boolean isSameType(PieceType type) { - return this.type.equals(type); - } - - @Override - public PieceType getType() { - return type; - } - - @Override - public int getScore() { - return score; - } - - protected Team getTeam() { - return this.team; - } -} diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index 9e82e1b4ba..cf59c888ee 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -9,7 +9,7 @@ import java.util.ArrayList; import java.util.List; -public class Cha extends AbstractPiece { +public class Cha extends Piece { private static final int SCORE = 13; diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index 8e9acbc800..c640700e74 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -9,7 +9,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Jang extends AbstractPiece { +public class Jang extends Piece { private static final int MAX_DISTANCE = 1; diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index 15f65115b6..6f512cb705 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -9,7 +9,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Jol extends AbstractPiece { +public class Jol extends Piece { private static final int SCORE = 2; private static final int MAX_DISTANCE = 1; diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index 5e0d299ae4..7ebd99ee0b 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -6,7 +6,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Ma extends AbstractPiece { +public class Ma extends Piece { private static final int SCORE = 5; diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index 02beaa9935..82c460ee46 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -10,7 +10,7 @@ import java.util.ArrayList; import java.util.List; -public class Pho extends AbstractPiece { +public class Pho extends Piece { private static final int SCORE = 7; diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index cd2d33fc55..854f5728af 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -5,12 +5,45 @@ import janggi.domain.point.Route; import janggi.domain.status.Team; -public interface Piece { - boolean canMove(Route route); - boolean isSameTeam(Team team); - boolean isSameType(PieceType type); - boolean canCapture(Piece target); - Points getRoutePoints(Point from, Point to); - PieceType getType(); - int getScore(); +public abstract class Piece { + + private final Team team; + private final PieceType type; + private final int score; + + public Piece(int score, Team team, PieceType type) { + this.score = score; + this.team = team; + this.type = type; + } + + public abstract Points getRoutePoints(Point from, Point to); + + public boolean canCapture(Piece target) { + return true; + } + + public boolean canMove(Route route) { + return route.isEmpty(); + } + + public boolean isSameTeam(Team team) { + return this.team.equals(team); + } + + public boolean isSameType(PieceType type) { + return this.type.equals(type); + } + + public PieceType getType() { + return type; + } + + public int getScore() { + return score; + } + + protected Team getTeam() { + return this.team; + } } diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index 4a1987b9f6..27e1ef9f65 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -9,7 +9,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Sa extends AbstractPiece { +public class Sa extends Piece { private static final int SCORE = 3; private static final int MAX_DISTANCE = 1; diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index ed552ad4ca..b6c73af5e6 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -6,7 +6,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Sang extends AbstractPiece { +public class Sang extends Piece { private static final int SCORE = 3; From 4878c6dc18153a917e28738d758c371cc145ba54 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 09:10:58 +0900 Subject: [PATCH 044/110] =?UTF-8?q?docs(readme):=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 0b2f1aa156..31a6eb7a56 100644 --- a/README.md +++ b/README.md @@ -69,5 +69,3 @@ #### 구현되지 않은 기능 - 상마상마, 마상마상 등의 상차림 변경은 미구현 - 외통수 시 게임을 종료하는 기능 미구현(장을 잡을 때까지 게임 진행) -- 궁성을 구현하지 않아서, 장, 사의 이동 범위 제한이 현재는 없음 -- 궁성 내부에서의 기물마다의 특수한 이동 경로 또한 현재는 없음 From 1dc2d87edc52194857d99cbba03ae8c205bd65f8 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 11:10:07 +0900 Subject: [PATCH 045/110] =?UTF-8?q?docs(readme):=20DDL=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 --- README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/README.md b/README.md index 31a6eb7a56..d590e81c71 100644 --- a/README.md +++ b/README.md @@ -69,3 +69,82 @@ #### 구현되지 않은 기능 - 상마상마, 마상마상 등의 상차림 변경은 미구현 - 외통수 시 게임을 종료하는 기능 미구현(장을 잡을 때까지 게임 진행) + + +```mermaid +classDiagram + Piece <|.. Ma + Piece <|.. Cha + Piece <|.. Pho + Piece <|.. Sang + Piece <|.. Jang + Piece <|.. Sa + Piece <|.. Jol + Board -- Piece + GameTurn .. HanTurn + GameTurn .. ChoTurn + GameTurn .. FinishedGame + JanggiGame -- GameTurn + JanggiGame -- Board + + class Point { + int x + int y + of(int x, int y) + } + class Piece { + Team team + isSameTeam(Team team) + getRoute(Point from, Point to) + canMove(List route) + } + class Board { + Map~Point, Piece~ state + init() + move(Point from, Point to) + } + class JanggiGame { + Board board + GameTurn gameState + play() + } + class GameTurn { + Team team + <> + move() + } + class HanTurn { + Team han + move() + } + class ChoTurn { + Team cho + move() + } + class FinishedGame { + Team winner + move() + } +``` +```mermaid +erDiagram + GameRoom ||--o{ Piece : "contains (1:N)" + + GameRoom { + BIGINT id PK + VARCHAR current_turn + VARCHAR winner + DOUBLE cho_score + DOUBLE han_score + } + + Piece { + BIGINT id PK + BIGINT game_room_id FK + VARCHAR piece_name + VARCHAR team + INT row_pos + INT col_pos + } + +``` From 9cbd76196ad6e7d93293b151c2bce74afb8a5848 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 15:57:58 +0900 Subject: [PATCH 046/110] =?UTF-8?q?refactor(Piece):=20=EC=B6=94=EC=83=81?= =?UTF-8?q?=20=EA=B3=A8=EA=B2=A9=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84?= =?UTF-8?q?=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/AbstractNormalPiece.java | 71 +++++++++++++++++ .../janggi/domain/piece/AbstractPiece.java | 46 +++++++++++ .../domain/piece/AbstractStraightPiece.java | 79 +++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 src/main/java/janggi/domain/piece/AbstractNormalPiece.java create mode 100644 src/main/java/janggi/domain/piece/AbstractPiece.java create mode 100644 src/main/java/janggi/domain/piece/AbstractStraightPiece.java diff --git a/src/main/java/janggi/domain/piece/AbstractNormalPiece.java b/src/main/java/janggi/domain/piece/AbstractNormalPiece.java new file mode 100644 index 0000000000..625bcbd0b5 --- /dev/null +++ b/src/main/java/janggi/domain/piece/AbstractNormalPiece.java @@ -0,0 +1,71 @@ +package janggi.domain.piece; + +import static java.lang.Math.abs; + +import janggi.domain.piece.direction.CastleDirection; +import janggi.domain.point.Point; +import janggi.domain.point.Points; +import janggi.domain.point.Route; +import janggi.domain.status.Team; +import java.util.List; + +abstract class AbstractNormalPiece implements Piece { + + private static final int MAX_DISTANCE = 1; + + private final Team team; + private final PieceType type; + private final int score; + + AbstractNormalPiece(int score, Team team, PieceType type) { + this.team = team; + this.type = type; + this.score = score; + } + + @Override + public Points getRoutePoints(Point from, Point to) { + if (!from.inSameCastle(to)) { + throw new IllegalArgumentException("[ERROR] 궁성 밖으로 나갈 수 없습니다."); + } + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); + int distanceCol = abs(pathCol); + int distanceRow = abs(pathRow); + validateDistance(distanceCol, distanceRow); + CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); + Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); + return new Points(List.of(point)); + } + + @Override + public boolean canMove(Route route) { + return !route.hasAlly(team); + } + + @Override + public boolean isSameTeam(Team team) { + return this.team.equals(team); + } + + @Override + public boolean isSameType(PieceType type) { + return this.type.equals(type); + } + + @Override + public PieceType getType() { + return type; + } + + @Override + public int getScore() { + return score; + } + + private void validateDistance(int distanceCol, int distanceRow) { + if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } +} diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractPiece.java new file mode 100644 index 0000000000..64c19b685f --- /dev/null +++ b/src/main/java/janggi/domain/piece/AbstractPiece.java @@ -0,0 +1,46 @@ +package janggi.domain.piece; + +import janggi.domain.point.Point; +import janggi.domain.point.Points; +import janggi.domain.point.Route; +import janggi.domain.status.Team; + +public abstract class AbstractPiece implements Piece { + + private final Team team; + private final PieceType type; + private final int score; + + public AbstractPiece(int score, Team team, PieceType type) { + this.score = score; + this.team = team; + this.type = type; + } + + @Override + public abstract Points getRoutePoints(Point from, Point to); + + public boolean canMove(Route route) { + return route.isEmpty(); + } + + public boolean isSameTeam(Team team) { + return this.team.equals(team); + } + + public boolean isSameType(PieceType type) { + return this.type.equals(type); + } + + public PieceType getType() { + return type; + } + + public int getScore() { + return score; + } + + protected Team getTeam() { + return this.team; + } +} diff --git a/src/main/java/janggi/domain/piece/AbstractStraightPiece.java b/src/main/java/janggi/domain/piece/AbstractStraightPiece.java new file mode 100644 index 0000000000..9dcc5c9a4e --- /dev/null +++ b/src/main/java/janggi/domain/piece/AbstractStraightPiece.java @@ -0,0 +1,79 @@ +package janggi.domain.piece; + +import static java.lang.Math.abs; + +import janggi.domain.piece.direction.CastleDirection; +import janggi.domain.point.Point; +import janggi.domain.point.Points; +import janggi.domain.point.Route; +import janggi.domain.status.Team; +import java.util.ArrayList; +import java.util.List; + +public class AbstractStraightPiece implements Piece { + + private final Team team; + private final PieceType type; + private final int score; + + public AbstractStraightPiece(int score, Team team, PieceType type) { + this.team = team; + this.type = type; + this.score = score; + } + + @Override + public Points getRoutePoints(Point from, Point to) { + int pathCol = to.calculatePathColumn(from); + int pathRow = to.calculatePathRow(from); + int signCol = Integer.compare(pathCol, 0); + int signRow = Integer.compare(pathRow, 0); + + validateDirection(from, to, signCol, signRow, pathCol, pathRow); + + int distance = Math.max(abs(pathCol), abs(pathRow)); + + List points = new ArrayList<>(); + for (int i = 1; i < distance; i++) { + int nextCol = from.getColumn() + (signCol * i); + int nextRow = from.getRow() + (signRow * i); + points.add(Point.of(nextCol, nextRow)); + } + return new Points(points); + } + + @Override + public boolean canMove(Route route) { + return route.isEmpty(); + } + + @Override + public boolean isSameTeam(Team team) { + return this.team.equals(team); + } + + @Override + public boolean isSameType(PieceType type) { + return this.type.equals(type); + } + + @Override + public PieceType getType() { + return type; + } + + @Override + public int getScore() { + return score; + } + + private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { + if (from.inSameCastle(to)) { + CastleDirection.find(from, signCol, signRow); + return; + } + if (pathCol != 0 && pathRow !=0) { + throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); + } + } +} From 3e8cc8e4445e913b8b0f710e70c80f8f76aee8f0 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 15:58:02 +0900 Subject: [PATCH 047/110] =?UTF-8?q?refactor(Piece):=20=EC=B6=94=EC=83=81?= =?UTF-8?q?=20=EA=B3=A8=EA=B2=A9=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84?= =?UTF-8?q?=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Piece.java | 48 ++++---------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index 854f5728af..fe677a6880 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -5,45 +5,15 @@ import janggi.domain.point.Route; import janggi.domain.status.Team; -public abstract class Piece { - - private final Team team; - private final PieceType type; - private final int score; - - public Piece(int score, Team team, PieceType type) { - this.score = score; - this.team = team; - this.type = type; - } - - public abstract Points getRoutePoints(Point from, Point to); - - public boolean canCapture(Piece target) { +public interface Piece { + boolean canMove(Route route); + boolean isSameTeam(Team team); + boolean isSameType(PieceType type); + Points getRoutePoints(Point from, Point to); + PieceType getType(); + int getScore(); + + default boolean canCapture(Piece piece) { return true; } - - public boolean canMove(Route route) { - return route.isEmpty(); - } - - public boolean isSameTeam(Team team) { - return this.team.equals(team); - } - - public boolean isSameType(PieceType type) { - return this.type.equals(type); - } - - public PieceType getType() { - return type; - } - - public int getScore() { - return score; - } - - protected Team getTeam() { - return this.team; - } } From 29cce32d043030f00cb5e967fb19b2ffb0c98e4b Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 15:59:08 +0900 Subject: [PATCH 048/110] =?UTF-8?q?refactor(AbstractStraightPiece):=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=20=EA=B3=A8=EA=B2=A9=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=84=EB=A5=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Cha.java | 39 +-------------------- src/main/java/janggi/domain/piece/Pho.java | 40 +--------------------- 2 files changed, 2 insertions(+), 77 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Cha.java index cf59c888ee..caef327c27 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Cha.java @@ -1,49 +1,12 @@ package janggi.domain.piece; -import static java.lang.Math.abs; - -import janggi.domain.piece.direction.CastleDirection; -import janggi.domain.point.Point; -import janggi.domain.point.Points; import janggi.domain.status.Team; -import java.util.ArrayList; -import java.util.List; -public class Cha extends Piece { +public class Cha extends AbstractStraightPiece { private static final int SCORE = 13; public Cha(Team team) { super(SCORE, team, PieceType.CHA); } - - @Override - public Points getRoutePoints(Point from, Point to) { - int pathCol = to.calculatePathColumn(from); - int pathRow = to.calculatePathRow(from); - int signCol = Integer.compare(pathCol, 0); - int signRow = Integer.compare(pathRow, 0); - - validateDirection(from, to, signCol, signRow, pathCol, pathRow); - - int distance = Math.max(abs(pathCol), abs(pathRow)); - - List points = new ArrayList<>(); - for (int i = 1; i < distance; i++) { - int nextCol = from.getColumn() + (signCol * i); - int nextRow = from.getRow() + (signRow * i); - points.add(Point.of(nextCol, nextRow)); - } - return new Points(points); - } - - private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { - if (from.inSameCastle(to)) { - CastleDirection.find(from, signCol, signRow); - return; - } - if (pathCol != 0 && pathRow !=0) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } - } } diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Pho.java index 82c460ee46..d326981707 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Pho.java @@ -1,16 +1,9 @@ package janggi.domain.piece; -import static java.lang.Math.abs; - -import janggi.domain.piece.direction.CastleDirection; -import janggi.domain.point.Point; -import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.ArrayList; -import java.util.List; -public class Pho extends Piece { +public class Pho extends AbstractStraightPiece { private static final int SCORE = 7; @@ -18,26 +11,6 @@ public Pho(Team team) { super(SCORE, team, PieceType.PHO); } - @Override - public Points getRoutePoints(Point from, Point to) { - int pathCol = to.calculatePathColumn(from); - int pathRow = to.calculatePathRow(from); - int signCol = Integer.compare(pathCol, 0); - int signRow = Integer.compare(pathRow, 0); - - validateDirection(from, to, signCol, signRow, pathCol, pathRow); - - int distance = Math.max(abs(pathCol), abs(pathRow)); - - List points = new ArrayList<>(); - for (int i = 1; i < distance; i++) { - int nextCol = from.getColumn() + (signCol * i); - int nextRow = from.getRow() + (signRow * i); - points.add(Point.of(nextCol, nextRow)); - } - return new Points(points); - } - @Override public boolean canMove(Route route) { if (route.hasObstacle()) { @@ -50,15 +23,4 @@ public boolean canMove(Route route) { public boolean canCapture(Piece target) { return !target.isSameType(PieceType.PHO); } - - private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { - if (from.inSameCastle(to)) { - CastleDirection.find(from, signCol, signRow); - return; - } - - if (pathCol != 0 && pathRow !=0) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } - } } From cdb2bd00c11115bfb025c476ae1a4b089a2e04de Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 15:59:29 +0900 Subject: [PATCH 049/110] =?UTF-8?q?refactor(AbstractPiece):=20=EC=B6=94?= =?UTF-8?q?=EC=83=81=20=EA=B3=A8=EA=B2=A9=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EB=B6=84=EB=A5=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Jol.java | 2 +- src/main/java/janggi/domain/piece/Ma.java | 2 +- src/main/java/janggi/domain/piece/Sang.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index 6f512cb705..15f65115b6 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -9,7 +9,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Jol extends Piece { +public class Jol extends AbstractPiece { private static final int SCORE = 2; private static final int MAX_DISTANCE = 1; diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index 7ebd99ee0b..5e0d299ae4 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -6,7 +6,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Ma extends Piece { +public class Ma extends AbstractPiece { private static final int SCORE = 5; diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index b6c73af5e6..ed552ad4ca 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -6,7 +6,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Sang extends Piece { +public class Sang extends AbstractPiece { private static final int SCORE = 3; From 4bddfbb5c5db685b9f56f10422894db871fd5f2d Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 15:59:42 +0900 Subject: [PATCH 050/110] =?UTF-8?q?refactor(AbstractNormalPiece):=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=20=EA=B3=A8=EA=B2=A9=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=84=EB=A5=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Jang.java | 38 +-------------------- src/main/java/janggi/domain/piece/Sa.java | 36 +------------------ 2 files changed, 2 insertions(+), 72 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Jang.java index c640700e74..0f27356aae 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Jang.java @@ -1,45 +1,9 @@ package janggi.domain.piece; -import static java.lang.Math.abs; - -import janggi.domain.piece.direction.CastleDirection; -import janggi.domain.point.Point; -import janggi.domain.point.Points; -import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; - -public class Jang extends Piece { - - private static final int MAX_DISTANCE = 1; +public class Jang extends AbstractNormalPiece { public Jang(Team team) { super(0, team, PieceType.JANG); } - - @Override - public Points getRoutePoints(Point from, Point to) { - if (!from.inSameCastle(to)) { - throw new IllegalArgumentException("[ERROR] 장은 궁성 밖으로 나갈 수 없습니다."); - } - int pathCol = to.calculatePathColumn(from); - int pathRow = to.calculatePathRow(from); - int distanceCol = abs(pathCol); - int distanceRow = abs(pathRow); - validateDistance(distanceCol, distanceRow); - CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); - Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); - return new Points(List.of(point)); - } - - @Override - public boolean canMove(Route route) { - return !route.hasAlly(super.getTeam()); - } - - private void validateDistance(int distanceCol, int distanceRow) { - if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } - } } diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Sa.java index 27e1ef9f65..8c2b6e1a7f 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Sa.java @@ -1,46 +1,12 @@ package janggi.domain.piece; -import static java.lang.Math.abs; - -import janggi.domain.piece.direction.CastleDirection; -import janggi.domain.point.Point; -import janggi.domain.point.Points; -import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; -public class Sa extends Piece { +public class Sa extends AbstractNormalPiece { private static final int SCORE = 3; - private static final int MAX_DISTANCE = 1; public Sa(Team team) { super(SCORE, team, PieceType.SA); } - - @Override - public Points getRoutePoints(Point from, Point to) { - if (!from.inSameCastle(to)) { - throw new IllegalArgumentException("[ERROR] 사는 궁성 밖으로 나갈 수 없습니다."); - } - int pathCol = to.calculatePathColumn(from); - int pathRow = to.calculatePathRow(from); - int distanceCol = abs(pathCol); - int distanceRow = abs(pathRow); - validateDistance(distanceCol, distanceRow); - CastleDirection direction = CastleDirection.find(from, pathCol, pathRow); - Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); - return new Points(List.of(point)); - } - - @Override - public boolean canMove(Route route) { - return !route.hasAlly(super.getTeam()); - } - - private void validateDistance(int distanceCol, int distanceRow) { - if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { - throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); - } - } } From aca2eac462ad7ac920711ce1522073fe1a30c5e5 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:01:41 +0900 Subject: [PATCH 051/110] =?UTF-8?q?test(Ma):=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/piece/MaTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/janggi/domain/piece/MaTest.java b/src/test/java/janggi/domain/piece/MaTest.java index f86a423268..c0dd39957e 100644 --- a/src/test/java/janggi/domain/piece/MaTest.java +++ b/src/test/java/janggi/domain/piece/MaTest.java @@ -5,7 +5,6 @@ import janggi.domain.point.Point; import janggi.domain.point.Points; -import janggi.domain.point.Route; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From c1217e10013feb46f16e7ed576632c8267387b1c Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:02:16 +0900 Subject: [PATCH 052/110] =?UTF-8?q?test(AbstractNormalPiece):=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/janggi/domain/piece/JangTest.java | 2 +- src/test/java/janggi/domain/piece/SaTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/janggi/domain/piece/JangTest.java b/src/test/java/janggi/domain/piece/JangTest.java index d5ce39e0fd..2d6d96f932 100644 --- a/src/test/java/janggi/domain/piece/JangTest.java +++ b/src/test/java/janggi/domain/piece/JangTest.java @@ -31,6 +31,6 @@ void can_not_move_outside_castle() { assertThatThrownBy(() -> jang.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("[ERROR] 장은 궁성 밖으로 나갈 수 없습니다."); + .hasMessageContaining("[ERROR] 궁성 밖으로 나갈 수 없습니다."); } } diff --git a/src/test/java/janggi/domain/piece/SaTest.java b/src/test/java/janggi/domain/piece/SaTest.java index d78bd54484..1e85911e63 100644 --- a/src/test/java/janggi/domain/piece/SaTest.java +++ b/src/test/java/janggi/domain/piece/SaTest.java @@ -31,6 +31,6 @@ void can_not_move_outside_castle() { assertThatThrownBy(() -> sa.getRoutePoints(from, to)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("[ERROR] 사는 궁성 밖으로 나갈 수 없습니다."); + .hasMessageContaining("[ERROR] 궁성 밖으로 나갈 수 없습니다."); } } From c4adcf96dd629b70eaad903b251ecc29cada6787 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:21:32 +0900 Subject: [PATCH 053/110] =?UTF-8?q?refactor(Jol):=20=EC=B6=94=EC=83=81=20?= =?UTF-8?q?=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/Jol.java | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Jol.java index 15f65115b6..bde27d32ad 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Jol.java @@ -9,13 +9,17 @@ import janggi.domain.status.Team; import java.util.List; -public class Jol extends AbstractPiece { +public class Jol implements Piece { - private static final int SCORE = 2; private static final int MAX_DISTANCE = 1; + private static final int SCORE = 2; + + private final Team team; + private final PieceType type; public Jol(Team team) { - super(SCORE, team, PieceType.JOL); + this.team = team; + this.type = PieceType.JOL; } @Override @@ -39,11 +43,31 @@ public Points getRoutePoints(Point from, Point to) { @Override public boolean canMove(Route route) { - return !route.hasAlly(super.getTeam()); + return !route.hasAlly(team); + } + + @Override + public boolean isSameTeam(Team team) { + return this.team.equals(team); + } + + @Override + public boolean isSameType(PieceType type) { + return this.type.equals(type); + } + + @Override + public PieceType getType() { + return type; + } + + @Override + public int getScore() { + return SCORE; } private void validateForward(int signRow) { - if ((super.getTeam().equals(Team.CHO) && signRow < 0) || (super.getTeam().equals(Team.HAN) && signRow > 0)) { + if ((team.equals(Team.CHO) && signRow < 0) || (team.equals(Team.HAN) && signRow > 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } } From 40f5065e38d99f92fe4b8553eb1c8c22a5f6fd77 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:22:20 +0900 Subject: [PATCH 054/110] =?UTF-8?q?refactor(AbstractFixedStepPiece):=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{AbstractPiece.java => AbstractFixedStepPiece.java} | 8 ++------ src/main/java/janggi/domain/piece/Ma.java | 2 +- src/main/java/janggi/domain/piece/Sang.java | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) rename src/main/java/janggi/domain/piece/{AbstractPiece.java => AbstractFixedStepPiece.java} (81%) diff --git a/src/main/java/janggi/domain/piece/AbstractPiece.java b/src/main/java/janggi/domain/piece/AbstractFixedStepPiece.java similarity index 81% rename from src/main/java/janggi/domain/piece/AbstractPiece.java rename to src/main/java/janggi/domain/piece/AbstractFixedStepPiece.java index 64c19b685f..f41f6f6916 100644 --- a/src/main/java/janggi/domain/piece/AbstractPiece.java +++ b/src/main/java/janggi/domain/piece/AbstractFixedStepPiece.java @@ -5,13 +5,13 @@ import janggi.domain.point.Route; import janggi.domain.status.Team; -public abstract class AbstractPiece implements Piece { +public abstract class AbstractFixedStepPiece implements Piece { private final Team team; private final PieceType type; private final int score; - public AbstractPiece(int score, Team team, PieceType type) { + public AbstractFixedStepPiece(int score, Team team, PieceType type) { this.score = score; this.team = team; this.type = type; @@ -39,8 +39,4 @@ public PieceType getType() { public int getScore() { return score; } - - protected Team getTeam() { - return this.team; - } } diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Ma.java index 5e0d299ae4..ecf14a0fe6 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Ma.java @@ -6,7 +6,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Ma extends AbstractPiece { +public class Ma extends AbstractFixedStepPiece { private static final int SCORE = 5; diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Sang.java index ed552ad4ca..47c2174be2 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Sang.java @@ -6,7 +6,7 @@ import janggi.domain.status.Team; import java.util.List; -public class Sang extends AbstractPiece { +public class Sang extends AbstractFixedStepPiece { private static final int SCORE = 3; From 30d33bd11afc13556abe10a204309acffe7b0968 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:40:09 +0900 Subject: [PATCH 055/110] =?UTF-8?q?feat(init):=20DDL=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/init.sql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/resources/init.sql diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql new file mode 100644 index 0000000000..017a0e3dc4 --- /dev/null +++ b/src/main/resources/init.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS game_room( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + current_turn VARCHAR(10) NOT NULL, + winner VARCHAR(10), + cha_score DOUBLE, + han_score DOUBLE +); +CREATE TABLE IF NOT EXISTS piece( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + game_room_id BIGINT NOT NULL, + piece_name VARCHAR(10) NOT NULL, + team VARCHAR(10) NOT NULL, + row_pos INT NOT NULL, + col_pos INT NOT NULL, + FOREIGN KEY (game_room_id) REFERENCES game_room(id) ON DELETE CASCADE +); From 122afad41a97630f682ba7337b359e7dba6c4719 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:40:25 +0900 Subject: [PATCH 056/110] =?UTF-8?q?refactor(init):=20DDL=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/infra/JdbcBoardRepository.java | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 598b4324f9..4ee4692c8b 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -41,7 +41,6 @@ public JdbcBoardRepository() { url = properties.getProperty("db.url"); username = properties.getProperty("db.username"); password = properties.getProperty("db.password"); - initTable(); } catch (IOException e) { throw new RuntimeException(e); } @@ -99,37 +98,6 @@ private Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } - private void initTable() { - String createGameRoom = """ - CREATE TABLE IF NOT EXISTS game_room( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - current_turn VARCHAR(10) NOT NULL, - winner VARCHAR(10), - cha_score DOUBLE, - han_score DOUBLE - ) - """; - - String createPiece = """ - CREATE TABLE IF NOT EXISTS piece( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - game_room_id BIGINT NOT NULL, - piece_name VARCHAR(10) NOT NULL, - team VARCHAR(10) NOT NULL, - row_pos INT NOT NULL, - col_pos INT NOT NULL, - FOREIGN KEY (game_room_id) REFERENCES game_room(id) ON DELETE CASCADE - ) - """; - try(Connection connection = getConnection()) { - Statement statement = connection.createStatement(); - statement.execute(createGameRoom); - statement.execute(createPiece); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - private static void addPieceData(List> pieces, int i, List data) { for (int j = 0; j < pieces.get(i).size(); j++) { Piece piece = pieces.get(i).get(j); From 10f102400de00d7e506d24a468ac4d6c3c0614dc Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Wed, 1 Apr 2026 16:45:24 +0900 Subject: [PATCH 057/110] =?UTF-8?q?chore(Piece):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/domain/piece/{ => Implementation}/Cha.java | 4 +++- .../janggi/domain/piece/{ => Implementation}/Jang.java | 4 +++- .../janggi/domain/piece/{ => Implementation}/Jol.java | 4 +++- .../janggi/domain/piece/{ => Implementation}/Ma.java | 4 +++- .../janggi/domain/piece/{ => Implementation}/Pho.java | 5 ++++- .../janggi/domain/piece/{ => Implementation}/Sa.java | 4 +++- .../janggi/domain/piece/{ => Implementation}/Sang.java | 4 +++- src/main/java/janggi/domain/piece/PieceFactory.java | 7 +++++++ .../piece/{ => template}/AbstractFixedStepPiece.java | 4 +++- .../piece/{ => template}/AbstractNormalPiece.java | 8 +++++--- .../piece/{ => template}/AbstractStraightPiece.java | 4 +++- src/test/java/janggi/domain/board/BoardTest.java | 10 +++++----- src/test/java/janggi/domain/piece/ChaTest.java | 1 + src/test/java/janggi/domain/piece/JangTest.java | 1 + src/test/java/janggi/domain/piece/JolTest.java | 1 + src/test/java/janggi/domain/piece/MaTest.java | 1 + src/test/java/janggi/domain/piece/PhoTest.java | 2 ++ src/test/java/janggi/domain/piece/SaTest.java | 1 + src/test/java/janggi/domain/piece/SangTest.java | 1 + src/test/java/janggi/domain/status/ChoTurnTest.java | 4 ++-- src/test/java/janggi/domain/status/HanTurnTest.java | 4 ++-- 21 files changed, 57 insertions(+), 21 deletions(-) rename src/main/java/janggi/domain/piece/{ => Implementation}/Cha.java (59%) rename src/main/java/janggi/domain/piece/{ => Implementation}/Jang.java (53%) rename src/main/java/janggi/domain/piece/{ => Implementation}/Jol.java (95%) rename src/main/java/janggi/domain/piece/{ => Implementation}/Ma.java (84%) rename src/main/java/janggi/domain/piece/{ => Implementation}/Pho.java (75%) rename src/main/java/janggi/domain/piece/{ => Implementation}/Sa.java (59%) rename src/main/java/janggi/domain/piece/{ => Implementation}/Sang.java (87%) rename src/main/java/janggi/domain/piece/{ => template}/AbstractFixedStepPiece.java (89%) rename src/main/java/janggi/domain/piece/{ => template}/AbstractNormalPiece.java (88%) rename src/main/java/janggi/domain/piece/{ => template}/AbstractStraightPiece.java (95%) diff --git a/src/main/java/janggi/domain/piece/Cha.java b/src/main/java/janggi/domain/piece/Implementation/Cha.java similarity index 59% rename from src/main/java/janggi/domain/piece/Cha.java rename to src/main/java/janggi/domain/piece/Implementation/Cha.java index caef327c27..311a230639 100644 --- a/src/main/java/janggi/domain/piece/Cha.java +++ b/src/main/java/janggi/domain/piece/Implementation/Cha.java @@ -1,5 +1,7 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; +import janggi.domain.piece.PieceType; +import janggi.domain.piece.template.AbstractStraightPiece; import janggi.domain.status.Team; public class Cha extends AbstractStraightPiece { diff --git a/src/main/java/janggi/domain/piece/Jang.java b/src/main/java/janggi/domain/piece/Implementation/Jang.java similarity index 53% rename from src/main/java/janggi/domain/piece/Jang.java rename to src/main/java/janggi/domain/piece/Implementation/Jang.java index 0f27356aae..c7a1bb9e02 100644 --- a/src/main/java/janggi/domain/piece/Jang.java +++ b/src/main/java/janggi/domain/piece/Implementation/Jang.java @@ -1,5 +1,7 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; +import janggi.domain.piece.PieceType; +import janggi.domain.piece.template.AbstractNormalPiece; import janggi.domain.status.Team; public class Jang extends AbstractNormalPiece { diff --git a/src/main/java/janggi/domain/piece/Jol.java b/src/main/java/janggi/domain/piece/Implementation/Jol.java similarity index 95% rename from src/main/java/janggi/domain/piece/Jol.java rename to src/main/java/janggi/domain/piece/Implementation/Jol.java index bde27d32ad..47a8876baf 100644 --- a/src/main/java/janggi/domain/piece/Jol.java +++ b/src/main/java/janggi/domain/piece/Implementation/Jol.java @@ -1,7 +1,9 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; import static java.lang.Math.abs; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; diff --git a/src/main/java/janggi/domain/piece/Ma.java b/src/main/java/janggi/domain/piece/Implementation/Ma.java similarity index 84% rename from src/main/java/janggi/domain/piece/Ma.java rename to src/main/java/janggi/domain/piece/Implementation/Ma.java index ecf14a0fe6..45c3d71520 100644 --- a/src/main/java/janggi/domain/piece/Ma.java +++ b/src/main/java/janggi/domain/piece/Implementation/Ma.java @@ -1,6 +1,8 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; +import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.MaDirection; +import janggi.domain.piece.template.AbstractFixedStepPiece; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; diff --git a/src/main/java/janggi/domain/piece/Pho.java b/src/main/java/janggi/domain/piece/Implementation/Pho.java similarity index 75% rename from src/main/java/janggi/domain/piece/Pho.java rename to src/main/java/janggi/domain/piece/Implementation/Pho.java index d326981707..c8c559e19d 100644 --- a/src/main/java/janggi/domain/piece/Pho.java +++ b/src/main/java/janggi/domain/piece/Implementation/Pho.java @@ -1,5 +1,8 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; +import janggi.domain.piece.template.AbstractStraightPiece; import janggi.domain.point.Route; import janggi.domain.status.Team; diff --git a/src/main/java/janggi/domain/piece/Sa.java b/src/main/java/janggi/domain/piece/Implementation/Sa.java similarity index 59% rename from src/main/java/janggi/domain/piece/Sa.java rename to src/main/java/janggi/domain/piece/Implementation/Sa.java index 8c2b6e1a7f..1175ac9563 100644 --- a/src/main/java/janggi/domain/piece/Sa.java +++ b/src/main/java/janggi/domain/piece/Implementation/Sa.java @@ -1,5 +1,7 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; +import janggi.domain.piece.PieceType; +import janggi.domain.piece.template.AbstractNormalPiece; import janggi.domain.status.Team; public class Sa extends AbstractNormalPiece { diff --git a/src/main/java/janggi/domain/piece/Sang.java b/src/main/java/janggi/domain/piece/Implementation/Sang.java similarity index 87% rename from src/main/java/janggi/domain/piece/Sang.java rename to src/main/java/janggi/domain/piece/Implementation/Sang.java index 47c2174be2..f846d9ace4 100644 --- a/src/main/java/janggi/domain/piece/Sang.java +++ b/src/main/java/janggi/domain/piece/Implementation/Sang.java @@ -1,6 +1,8 @@ -package janggi.domain.piece; +package janggi.domain.piece.Implementation; +import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.SangDirection; +import janggi.domain.piece.template.AbstractFixedStepPiece; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; diff --git a/src/main/java/janggi/domain/piece/PieceFactory.java b/src/main/java/janggi/domain/piece/PieceFactory.java index 8d8991af30..9dd474821c 100644 --- a/src/main/java/janggi/domain/piece/PieceFactory.java +++ b/src/main/java/janggi/domain/piece/PieceFactory.java @@ -1,5 +1,12 @@ package janggi.domain.piece; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Jang; +import janggi.domain.piece.Implementation.Jol; +import janggi.domain.piece.Implementation.Ma; +import janggi.domain.piece.Implementation.Pho; +import janggi.domain.piece.Implementation.Sa; +import janggi.domain.piece.Implementation.Sang; import janggi.domain.status.Team; import java.util.Map; import java.util.function.Function; diff --git a/src/main/java/janggi/domain/piece/AbstractFixedStepPiece.java b/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java similarity index 89% rename from src/main/java/janggi/domain/piece/AbstractFixedStepPiece.java rename to src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java index f41f6f6916..1db5d80dca 100644 --- a/src/main/java/janggi/domain/piece/AbstractFixedStepPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java @@ -1,5 +1,7 @@ -package janggi.domain.piece; +package janggi.domain.piece.template; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; diff --git a/src/main/java/janggi/domain/piece/AbstractNormalPiece.java b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java similarity index 88% rename from src/main/java/janggi/domain/piece/AbstractNormalPiece.java rename to src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java index 625bcbd0b5..9dfcfe7218 100644 --- a/src/main/java/janggi/domain/piece/AbstractNormalPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java @@ -1,7 +1,9 @@ -package janggi.domain.piece; +package janggi.domain.piece.template; import static java.lang.Math.abs; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; @@ -9,7 +11,7 @@ import janggi.domain.status.Team; import java.util.List; -abstract class AbstractNormalPiece implements Piece { +public abstract class AbstractNormalPiece implements Piece { private static final int MAX_DISTANCE = 1; @@ -17,7 +19,7 @@ abstract class AbstractNormalPiece implements Piece { private final PieceType type; private final int score; - AbstractNormalPiece(int score, Team team, PieceType type) { + public AbstractNormalPiece(int score, Team team, PieceType type) { this.team = team; this.type = type; this.score = score; diff --git a/src/main/java/janggi/domain/piece/AbstractStraightPiece.java b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java similarity index 95% rename from src/main/java/janggi/domain/piece/AbstractStraightPiece.java rename to src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java index 9dcc5c9a4e..97017d4158 100644 --- a/src/main/java/janggi/domain/piece/AbstractStraightPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java @@ -1,7 +1,9 @@ -package janggi.domain.piece; +package janggi.domain.piece.template; import static java.lang.Math.abs; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.CastleDirection; import janggi.domain.point.Point; import janggi.domain.point.Points; diff --git a/src/test/java/janggi/domain/board/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java index c87d855eea..6d1dd9aef4 100644 --- a/src/test/java/janggi/domain/board/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -1,11 +1,11 @@ package janggi.domain.board; -import janggi.domain.piece.Cha; -import janggi.domain.piece.Jol; -import janggi.domain.piece.Ma; -import janggi.domain.piece.Pho; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Jol; +import janggi.domain.piece.Implementation.Ma; +import janggi.domain.piece.Implementation.Pho; import janggi.domain.piece.Piece; -import janggi.domain.piece.Sang; +import janggi.domain.piece.Implementation.Sang; import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.LinkedHashMap; diff --git a/src/test/java/janggi/domain/piece/ChaTest.java b/src/test/java/janggi/domain/piece/ChaTest.java index 236efb0233..6dd63e3e97 100644 --- a/src/test/java/janggi/domain/piece/ChaTest.java +++ b/src/test/java/janggi/domain/piece/ChaTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.Implementation.Cha; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; diff --git a/src/test/java/janggi/domain/piece/JangTest.java b/src/test/java/janggi/domain/piece/JangTest.java index 2d6d96f932..74be45aa55 100644 --- a/src/test/java/janggi/domain/piece/JangTest.java +++ b/src/test/java/janggi/domain/piece/JangTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; +import janggi.domain.piece.Implementation.Jang; import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/piece/JolTest.java b/src/test/java/janggi/domain/piece/JolTest.java index 501b15fe3c..f0e1070bd4 100644 --- a/src/test/java/janggi/domain/piece/JolTest.java +++ b/src/test/java/janggi/domain/piece/JolTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import janggi.domain.piece.Implementation.Jol; import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/piece/MaTest.java b/src/test/java/janggi/domain/piece/MaTest.java index c0dd39957e..7e0f5959f9 100644 --- a/src/test/java/janggi/domain/piece/MaTest.java +++ b/src/test/java/janggi/domain/piece/MaTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.Implementation.Ma; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index 833756e074..d1f0b42f3f 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -4,6 +4,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import janggi.domain.board.Board; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Pho; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.point.Route; diff --git a/src/test/java/janggi/domain/piece/SaTest.java b/src/test/java/janggi/domain/piece/SaTest.java index 1e85911e63..9f813d7c40 100644 --- a/src/test/java/janggi/domain/piece/SaTest.java +++ b/src/test/java/janggi/domain/piece/SaTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; +import janggi.domain.piece.Implementation.Sa; import janggi.domain.point.Point; import janggi.domain.status.Team; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/janggi/domain/piece/SangTest.java b/src/test/java/janggi/domain/piece/SangTest.java index c3d3e373db..92f7231559 100644 --- a/src/test/java/janggi/domain/piece/SangTest.java +++ b/src/test/java/janggi/domain/piece/SangTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import janggi.domain.piece.Implementation.Sang; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; diff --git a/src/test/java/janggi/domain/status/ChoTurnTest.java b/src/test/java/janggi/domain/status/ChoTurnTest.java index 56d3795287..f375472cbb 100644 --- a/src/test/java/janggi/domain/status/ChoTurnTest.java +++ b/src/test/java/janggi/domain/status/ChoTurnTest.java @@ -5,8 +5,8 @@ import janggi.domain.board.Board; import janggi.domain.point.Point; -import janggi.domain.piece.Cha; -import janggi.domain.piece.Jang; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Jang; import janggi.domain.piece.Piece; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/test/java/janggi/domain/status/HanTurnTest.java b/src/test/java/janggi/domain/status/HanTurnTest.java index 4e2358bf30..c39a7f95c8 100644 --- a/src/test/java/janggi/domain/status/HanTurnTest.java +++ b/src/test/java/janggi/domain/status/HanTurnTest.java @@ -5,8 +5,8 @@ import janggi.domain.board.Board; import janggi.domain.point.Point; -import janggi.domain.piece.Cha; -import janggi.domain.piece.Jang; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Jang; import janggi.domain.piece.Piece; import java.util.LinkedHashMap; import java.util.Map; From bc289da32adcb447b927fb36ba3c7bb07fa569ed Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Thu, 2 Apr 2026 22:58:33 +0900 Subject: [PATCH 058/110] =?UTF-8?q?chore(util):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/presentation/JanggiGameController.java | 4 ++-- src/main/java/janggi/presentation/ui/InputView.java | 4 ++-- src/main/java/janggi/{ => presentation}/util/Console.java | 2 +- src/main/java/janggi/{ => presentation}/util/FileParser.java | 2 +- src/main/java/janggi/{ => presentation}/util/FileReader.java | 2 +- src/main/java/janggi/{ => presentation}/util/Parser.java | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/janggi/{ => presentation}/util/Console.java (93%) rename src/main/java/janggi/{ => presentation}/util/FileParser.java (89%) rename src/main/java/janggi/{ => presentation}/util/FileReader.java (97%) rename src/main/java/janggi/{ => presentation}/util/Parser.java (96%) diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index c64e738399..5b26b5ba68 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -9,8 +9,8 @@ import janggi.presentation.dto.PositionInfo; import janggi.presentation.ui.InputView; import janggi.presentation.ui.OutputView; -import janggi.util.Console; -import janggi.util.FileParser; +import janggi.presentation.util.Console; +import janggi.presentation.util.FileParser; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; diff --git a/src/main/java/janggi/presentation/ui/InputView.java b/src/main/java/janggi/presentation/ui/InputView.java index ef8f52c2e4..d27a671c3d 100644 --- a/src/main/java/janggi/presentation/ui/InputView.java +++ b/src/main/java/janggi/presentation/ui/InputView.java @@ -2,8 +2,8 @@ import janggi.domain.status.Team; import janggi.presentation.dto.MoveCommand; -import janggi.util.Console; -import janggi.util.Parser; +import janggi.presentation.util.Console; +import janggi.presentation.util.Parser; import java.util.Map; public class InputView { diff --git a/src/main/java/janggi/util/Console.java b/src/main/java/janggi/presentation/util/Console.java similarity index 93% rename from src/main/java/janggi/util/Console.java rename to src/main/java/janggi/presentation/util/Console.java index f106cc1526..8f79328383 100644 --- a/src/main/java/janggi/util/Console.java +++ b/src/main/java/janggi/presentation/util/Console.java @@ -1,4 +1,4 @@ -package janggi.util; +package janggi.presentation.util; import java.util.Scanner; diff --git a/src/main/java/janggi/util/FileParser.java b/src/main/java/janggi/presentation/util/FileParser.java similarity index 89% rename from src/main/java/janggi/util/FileParser.java rename to src/main/java/janggi/presentation/util/FileParser.java index d50c36e4d9..0a96eb1b63 100644 --- a/src/main/java/janggi/util/FileParser.java +++ b/src/main/java/janggi/presentation/util/FileParser.java @@ -1,4 +1,4 @@ -package janggi.util; +package janggi.presentation.util; import janggi.presentation.dto.PositionInfo; import java.util.List; diff --git a/src/main/java/janggi/util/FileReader.java b/src/main/java/janggi/presentation/util/FileReader.java similarity index 97% rename from src/main/java/janggi/util/FileReader.java rename to src/main/java/janggi/presentation/util/FileReader.java index 40a2d634c7..dc8b476991 100644 --- a/src/main/java/janggi/util/FileReader.java +++ b/src/main/java/janggi/presentation/util/FileReader.java @@ -1,4 +1,4 @@ -package janggi.util; +package janggi.presentation.util; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/main/java/janggi/util/Parser.java b/src/main/java/janggi/presentation/util/Parser.java similarity index 96% rename from src/main/java/janggi/util/Parser.java rename to src/main/java/janggi/presentation/util/Parser.java index 697e3eb9b0..c3e19e235d 100644 --- a/src/main/java/janggi/util/Parser.java +++ b/src/main/java/janggi/presentation/util/Parser.java @@ -1,4 +1,4 @@ -package janggi.util; +package janggi.presentation.util; import janggi.domain.point.Point; import janggi.domain.status.Team; From eb438b0c9d71f6075c07b38c6f429ad4eee8b96f Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Thu, 2 Apr 2026 23:05:11 +0900 Subject: [PATCH 059/110] =?UTF-8?q?refactor(Pho):=20=EC=9E=A5=EC=95=A0?= =?UTF-8?q?=EB=AC=BC=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/point/Route.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/point/Route.java b/src/main/java/janggi/domain/point/Route.java index 7883f87b48..679760e80d 100644 --- a/src/main/java/janggi/domain/point/Route.java +++ b/src/main/java/janggi/domain/point/Route.java @@ -20,7 +20,7 @@ public boolean isEmpty() { } public boolean hasObstacle() { - return pieces.size() > OBSTACLE_SIZE; + return pieces.size() != OBSTACLE_SIZE; } public boolean hasSameType(PieceType type) { From e436cf82ee03acced47abdc52998d4846870e0e4 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Thu, 2 Apr 2026 23:12:36 +0900 Subject: [PATCH 060/110] =?UTF-8?q?refactor(AbstractStraightPiece):=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A7=80?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EC=B6=94=EC=83=81=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/piece/Implementation/Cha.java | 5 +++++ .../janggi/domain/piece/template/AbstractStraightPiece.java | 6 ++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Implementation/Cha.java b/src/main/java/janggi/domain/piece/Implementation/Cha.java index 311a230639..154333f6dc 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Cha.java +++ b/src/main/java/janggi/domain/piece/Implementation/Cha.java @@ -2,6 +2,7 @@ import janggi.domain.piece.PieceType; import janggi.domain.piece.template.AbstractStraightPiece; +import janggi.domain.point.Route; import janggi.domain.status.Team; public class Cha extends AbstractStraightPiece { @@ -11,4 +12,8 @@ public class Cha extends AbstractStraightPiece { public Cha(Team team) { super(SCORE, team, PieceType.CHA); } + + public boolean canMove(Route route) { + return route.isEmpty(); + } } diff --git a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java index 97017d4158..5b31c119f6 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java @@ -12,7 +12,7 @@ import java.util.ArrayList; import java.util.List; -public class AbstractStraightPiece implements Piece { +public abstract class AbstractStraightPiece implements Piece { private final Team team; private final PieceType type; @@ -45,9 +45,7 @@ public Points getRoutePoints(Point from, Point to) { } @Override - public boolean canMove(Route route) { - return route.isEmpty(); - } + public abstract boolean canMove(Route route); @Override public boolean isSameTeam(Team team) { From ad666f387673db33a7e9d366d0c7f291e37e4be4 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Thu, 2 Apr 2026 23:13:08 +0900 Subject: [PATCH 061/110] =?UTF-8?q?feat(application.properties):=20DB=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/resources/application.properties diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000000..951757ed11 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,3 @@ +db.url=jdbc:h2:./janggi;AUTO_SERVER=TRUE;INIT=RUNSCRIPT FROM 'classpath:init.sql' +db.username=sa +db.password= From ebb4d6e1d7f305f16b3d4d1b72389b1a793f4197 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Thu, 2 Apr 2026 23:42:42 +0900 Subject: [PATCH 062/110] =?UTF-8?q?refactor(SangDirection):=20=EC=9D=B8?= =?UTF-8?q?=EC=8A=A4=ED=84=B4=EC=8A=A4=20=EB=B3=80=EC=88=98=20=EC=A4=84?= =?UTF-8?q?=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/Implementation/Sang.java | 15 ++- .../janggi/domain/piece/direction/Offset.java | 7 ++ .../domain/piece/direction/SangDirection.java | 101 ++++++++++++------ 3 files changed, 80 insertions(+), 43 deletions(-) create mode 100644 src/main/java/janggi/domain/piece/direction/Offset.java diff --git a/src/main/java/janggi/domain/piece/Implementation/Sang.java b/src/main/java/janggi/domain/piece/Implementation/Sang.java index f846d9ace4..0b3b840d7f 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Sang.java +++ b/src/main/java/janggi/domain/piece/Implementation/Sang.java @@ -1,11 +1,13 @@ package janggi.domain.piece.Implementation; import janggi.domain.piece.PieceType; +import janggi.domain.piece.direction.Offset; import janggi.domain.piece.direction.SangDirection; import janggi.domain.piece.template.AbstractFixedStepPiece; import janggi.domain.point.Point; import janggi.domain.point.Points; import janggi.domain.status.Team; +import java.util.ArrayList; import java.util.List; public class Sang extends AbstractFixedStepPiece { @@ -23,14 +25,11 @@ public Points getRoutePoints(Point from, Point to) { SangDirection direction = SangDirection.find(pathCol, pathRow); - Point routePoint1 = Point.of( - from.getColumn() + direction.getRoute1Col(), - from.getRow() + direction.getRoute1Row() - ); - Point routePoint2 = Point.of(from.getColumn() + direction.getRoute2Col(), - from.getRow() + direction.getRoute2Row() - ); + List points = new ArrayList<>(); + for (Offset offset : direction.getWaypoints()) { + points.add(Point.of(from.getColumn() + offset.directionColumn(), from.getRow() + offset.directionRow())); + } - return new Points(List.of(routePoint1, routePoint2)); + return new Points(points); } } diff --git a/src/main/java/janggi/domain/piece/direction/Offset.java b/src/main/java/janggi/domain/piece/direction/Offset.java new file mode 100644 index 0000000000..464f46bfb3 --- /dev/null +++ b/src/main/java/janggi/domain/piece/direction/Offset.java @@ -0,0 +1,7 @@ +package janggi.domain.piece.direction; + +public record Offset( + int directionColumn, + int directionRow +) { +} diff --git a/src/main/java/janggi/domain/piece/direction/SangDirection.java b/src/main/java/janggi/domain/piece/direction/SangDirection.java index 2d234ae271..61b118b794 100644 --- a/src/main/java/janggi/domain/piece/direction/SangDirection.java +++ b/src/main/java/janggi/domain/piece/direction/SangDirection.java @@ -1,54 +1,85 @@ package janggi.domain.piece.direction; import java.util.Arrays; +import java.util.List; public enum SangDirection { - UP_LEFT(-2, -3, 0, -1, -1, -2), - UP_RIGHT(2, -3, 0, -1, 1, -2), - DOWN_LEFT(-2, 3, 0, 1, -1, 2), - DOWN_RIGHT(2, 3, 0, 1, 1, 2), + UP_LEFT( + List.of( + new Offset(-2, -3), + new Offset(0, -1), + new Offset(-1, -2) + ) + ), + UP_RIGHT( + List.of( + new Offset(2, -3), + new Offset(0, -1), + new Offset(1, -2) + ) + ), + DOWN_LEFT( + List.of( + new Offset(-2, 3), + new Offset(0, 1), + new Offset(-1, 2) + ) + ), + DOWN_RIGHT( + List.of( + new Offset(2, 3), + new Offset(0, 1), + new Offset(1, 2) + ) + ), + LEFT_UP( + List.of( + new Offset(-3, -2), + new Offset(-1, 0), + new Offset(-2, -1) + ) + ), + LEFT_DOWN( + List.of( + new Offset(-3, 2), + new Offset(-1, 0), + new Offset(-2, 1) + ) + ), + RIGHT_UP( + List.of( + new Offset(3, -2), + new Offset(1, 0), + new Offset(2, -1) + ) + ), + RIGHT_DOWN( + List.of( + new Offset(3, 2), + new Offset(1, 0), + new Offset(2, 1) + ) + ); - LEFT_UP(-3, -2, -1, 0, -2, -1), - LEFT_DOWN(-3, 2, -1, 0, -2, 1), - RIGHT_UP(3, -2, 1, 0, 2, -1), - RIGHT_DOWN(3, 2, 1, 0, 2, 1); + private final List routes; - private final int targetCol; - private final int targetRow; - private final int route1Col; - private final int route1Row; - private final int route2Col; - private final int route2Row; - - SangDirection(int targetCol, int targetRow, int route1Col, int route1Row, int route2Col, int route2Row) { - this.targetCol = targetCol; - this.targetRow = targetRow; - this.route1Col = route1Col; - this.route1Row = route1Row; - this.route2Col = route2Col; - this.route2Row = route2Row; + SangDirection(List routes) { + this.routes = routes; } public static SangDirection find(int directionCol, int directionRow) { return Arrays.stream(values()) - .filter(dir -> dir.targetCol == directionCol && dir.targetRow == directionRow) + .filter(dir -> dir.getTarget().directionColumn() == directionCol + && dir.getTarget().directionRow() == directionRow) .findFirst() .orElseThrow(() -> new IllegalArgumentException("[ERROR] 상이 이동할 수 없는 방향입니다.")); } - public int getRoute1Col() { - return route1Col; - } - - public int getRoute1Row() { - return route1Row; - } - - public int getRoute2Col() { - return route2Col; + public List getWaypoints() { + return routes.subList(1, routes.size()); } - public int getRoute2Row() { - return route2Row; + private Offset getTarget() { + return routes.getFirst(); } } From 7b3374101987ec25fbdf42ea7034fac19533f490 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Thu, 2 Apr 2026 23:51:07 +0900 Subject: [PATCH 063/110] =?UTF-8?q?refactor(MaDirection):=20=EC=9D=B8?= =?UTF-8?q?=EC=8A=A4=ED=84=B4=EC=8A=A4=20=EB=B3=80=EC=88=98=20=EC=A4=84?= =?UTF-8?q?=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/Implementation/Ma.java | 3 +- .../domain/piece/direction/MaDirection.java | 79 +++++++++++++------ 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Implementation/Ma.java b/src/main/java/janggi/domain/piece/Implementation/Ma.java index 45c3d71520..b1d0284e69 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Ma.java +++ b/src/main/java/janggi/domain/piece/Implementation/Ma.java @@ -22,7 +22,8 @@ public Points getRoutePoints(Point from, Point to) { int pathY = to.calculatePathRow(from); MaDirection direction = MaDirection.find(pathX, pathY); - Point point = Point.of(from.getColumn() + direction.getRouteCol(), from.getRow() + direction.getRouteRow()); + + Point point = Point.of(from.getColumn() + direction.getWaypoint().directionColumn(), from.getRow() + direction.getWaypoint().directionRow()); return new Points(List.of(point)); } } diff --git a/src/main/java/janggi/domain/piece/direction/MaDirection.java b/src/main/java/janggi/domain/piece/direction/MaDirection.java index 7e3faa55d2..1eac28e033 100644 --- a/src/main/java/janggi/domain/piece/direction/MaDirection.java +++ b/src/main/java/janggi/domain/piece/direction/MaDirection.java @@ -1,41 +1,76 @@ package janggi.domain.piece.direction; import java.util.Arrays; +import java.util.List; public enum MaDirection { - UP_LEFT(-1, -2, 0, -1), - UP_RIGHT(1, -2, 0, -1), - DOWN_LEFT(-1, 2, 0, 1), - DOWN_RIGHT(1, 2, 0, 1), - LEFT_UP(-2, -1, -1, 0), - LEFT_DOWN(-2, 1, -1, 0), - RIGHT_UP(2, -1, 1, 0), - RIGHT_DOWN(2, 1, 1, 0); + UP_LEFT( + List.of( + new Offset(-1, -2), + new Offset(0, -1) + ) + ), + UP_RIGHT( + List.of( + new Offset(1, -2), + new Offset(0, -1) + ) + ), + DOWN_LEFT( + List.of( + new Offset(-1, 2), + new Offset(0, 1) + ) + ), + DOWN_RIGHT( + List.of( + new Offset(1, 2), + new Offset(0, 1) + ) + ), + LEFT_UP( + List.of( + new Offset(-2, -1), + new Offset(-1, 0) + ) + ), + LEFT_DOWN( + List.of( + new Offset(-2, 1), + new Offset(-1, 0) + ) + ), + RIGHT_UP( + List.of( + new Offset(2, -1), + new Offset(1, 0) + ) + ), + RIGHT_DOWN( + List.of( + new Offset(2, 1), + new Offset(1, 0) + ) + ); - private final int targetCol; - private final int targetRow; - private final int routeCol; - private final int routeRow; + List routes; - MaDirection(int targetCol, int targetRow, int routeCol, int routeRow) { - this.targetCol = targetCol; - this.targetRow = targetRow; - this.routeCol = routeCol; - this.routeRow = routeRow; + MaDirection(List routes) { + this.routes = routes; } public static MaDirection find(int directionCol, int directionRow) { return Arrays.stream(values()) - .filter(dir -> dir.targetCol == directionCol && dir.targetRow == directionRow) + .filter(dir -> dir.getTarget().directionColumn() == directionCol && dir.getTarget().directionRow() == directionRow) .findFirst() .orElseThrow(() -> new IllegalArgumentException("[ERROR] 마가 이동할 수 없는 방향입니다.")); } - public int getRouteCol() { - return routeCol; + public Offset getWaypoint() { + return routes.getLast(); } - public int getRouteRow() { - return routeRow; + private Offset getTarget() { + return routes.getFirst(); } } From 8f147b5b3ebbb9b91708108e703fa7855191addb Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 00:22:15 +0900 Subject: [PATCH 064/110] =?UTF-8?q?refactor(GameCommand):=20y,n=20?= =?UTF-8?q?=EB=AA=85=EB=A0=B9=EC=96=B4=20=EC=97=AD=ED=95=A0=20=EB=B6=80?= =?UTF-8?q?=EC=97=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/JanggiGameController.java | 13 +++++----- .../janggi/presentation/dto/GameCommand.java | 26 +++++++++++++++++++ .../janggi/presentation/ui/InputView.java | 5 ++-- 3 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 src/main/java/janggi/presentation/dto/GameCommand.java diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index 5b26b5ba68..87850ff9f8 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -5,6 +5,7 @@ import janggi.domain.piece.Piece; import janggi.domain.point.Point; import janggi.domain.status.Team; +import janggi.presentation.dto.GameCommand; import janggi.presentation.dto.MoveCommand; import janggi.presentation.dto.PositionInfo; import janggi.presentation.ui.InputView; @@ -47,13 +48,13 @@ private void playGame(Long roomId) { } } - private Long chooseBoard(String chosen) { - if (chosen.equals("n")) { - Long gameRoomId = InputView.chooseExistsGame(); - service.loadExistsBoard(gameRoomId); - return gameRoomId; + private Long chooseBoard(GameCommand command) { + if (command.isNewGame()) { + return service.startNewGame(readInitBoard()); } - return service.startNewGame(readInitBoard()); + Long gameRoomId = InputView.chooseExistsGame(); + service.loadExistsBoard(gameRoomId); + return gameRoomId; } private Board readInitBoard() { diff --git a/src/main/java/janggi/presentation/dto/GameCommand.java b/src/main/java/janggi/presentation/dto/GameCommand.java new file mode 100644 index 0000000000..6c144b7142 --- /dev/null +++ b/src/main/java/janggi/presentation/dto/GameCommand.java @@ -0,0 +1,26 @@ +package janggi.presentation.dto; + +import java.util.Arrays; + +public enum GameCommand { + NEW("y"), + + LOAD("n"); + + private final String input; + + GameCommand(String input) { + this.input = input; + } + + public static GameCommand from(String input) { + return Arrays.stream(values()) + .filter(command -> command.input.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("[ERROR] y 또는 n만 입력 가능합니다.")); + } + + public boolean isNewGame() { + return this == NEW; + } +} diff --git a/src/main/java/janggi/presentation/ui/InputView.java b/src/main/java/janggi/presentation/ui/InputView.java index d27a671c3d..53d46f2c4c 100644 --- a/src/main/java/janggi/presentation/ui/InputView.java +++ b/src/main/java/janggi/presentation/ui/InputView.java @@ -1,6 +1,7 @@ package janggi.presentation.ui; import janggi.domain.status.Team; +import janggi.presentation.dto.GameCommand; import janggi.presentation.dto.MoveCommand; import janggi.presentation.util.Console; import janggi.presentation.util.Parser; @@ -16,9 +17,9 @@ public class InputView { private InputView() { } - public static String chooseNewGame() { + public static GameCommand chooseNewGame() { System.out.println("새로운 장기 게임을 시작하시겠습니까?(y,n)"); - return Console.readLine(); + return GameCommand.from(Console.readLine()); } public static Long chooseExistsGame() { From 12bf254208817caed1ff4da7b8375361365397e1 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 00:22:40 +0900 Subject: [PATCH 065/110] =?UTF-8?q?style(JdbcBoardRepository):=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=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/infra/JdbcBoardRepository.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 4ee4692c8b..650cb0a8c3 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -18,7 +18,6 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -48,7 +47,7 @@ public JdbcBoardRepository() { @Override public Long save(JanggiGame game) { - try(Connection connection = getConnection()) { + try (Connection connection = getConnection()) { Long roomId = roomDao.save(GameRoomData.from(game), connection); List> pieces = game.getBoardStatus(); List data = new ArrayList<>(); @@ -64,7 +63,7 @@ public Long save(JanggiGame game) { @Override public void update(Long roomId, Point from, Point to, JanggiGame game) { - try(Connection connection = getConnection()) { + try (Connection connection = getConnection()) { roomDao.update(roomId, GameRoomData.from(game), connection); piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); @@ -75,7 +74,7 @@ public void update(Long roomId, Point from, Point to, JanggiGame game) { @Override public JanggiGame loadGame(Long gameRoomId) { - try(Connection connection = getConnection()) { + try (Connection connection = getConnection()) { GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection); List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); Map pieces = new LinkedHashMap<>(); From 92f051afddd288f715edea7bb6bc8a225fc9b32c Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 00:26:37 +0900 Subject: [PATCH 066/110] =?UTF-8?q?refactor(View):=20View=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 6 ++++- .../presentation/JanggiGameController.java | 26 +++++++++++-------- .../janggi/presentation/ui/InputView.java | 13 ++++------ .../janggi/presentation/ui/OutputView.java | 10 +++---- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index 175f0f3142..6c3a0648bc 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -4,6 +4,8 @@ import janggi.domain.board.BoardRepository; import janggi.infra.JdbcBoardRepository; import janggi.presentation.JanggiGameController; +import janggi.presentation.ui.InputView; +import janggi.presentation.ui.OutputView; import java.sql.SQLException; import org.h2.tools.Server; @@ -12,7 +14,9 @@ public static void main(String[] args) throws SQLException { Server server = Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start(); BoardRepository repository = new JdbcBoardRepository(); JanggiGameService service = new JanggiGameService(repository); - JanggiGameController controller = new JanggiGameController(service); + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + JanggiGameController controller = new JanggiGameController(service, inputView, outputView); controller.run(); server.stop(); } diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index 87850ff9f8..e0c0711d13 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -19,32 +19,36 @@ public class JanggiGameController { private final JanggiGameService service; + private final InputView inputView; + private final OutputView outputView; - public JanggiGameController(JanggiGameService service) { + public JanggiGameController(JanggiGameService service, InputView inputView, OutputView outputView) { this.service = service; + this.inputView = inputView; + this.outputView = outputView; } public void run() { - Long roomId = chooseBoard(InputView.chooseNewGame()); - OutputView.printStartGame(); - OutputView.printGameStatus(service.getBoardStatus()); - OutputView.printCurrentScore(service.getHanScore(), service.getChoScore()); + Long roomId = chooseBoard(inputView.chooseNewGame()); + outputView.printStartGame(); + outputView.printGameStatus(service.getBoardStatus()); + outputView.printCurrentScore(service.getHanScore(), service.getChoScore()); while (!service.isFinished()) { playGame(roomId); } - OutputView.printWinner(service.winner()); + outputView.printWinner(service.winner()); Console.close(); } private void playGame(Long roomId) { try { Team team = service.currentTurn(); - MoveCommand points = InputView.readPoints(team); + MoveCommand points = inputView.readPoints(team); service.play(roomId, points.from(), points.to()); - OutputView.printGameStatus(service.getBoardStatus()); - OutputView.printCurrentScore(service.getHanScore(), service.getChoScore()); + outputView.printGameStatus(service.getBoardStatus()); + outputView.printCurrentScore(service.getHanScore(), service.getChoScore()); } catch (IllegalArgumentException e) { - OutputView.printError(e.getMessage()); + outputView.printError(e.getMessage()); } } @@ -52,7 +56,7 @@ private Long chooseBoard(GameCommand command) { if (command.isNewGame()) { return service.startNewGame(readInitBoard()); } - Long gameRoomId = InputView.chooseExistsGame(); + Long gameRoomId = inputView.chooseExistsGame(); service.loadExistsBoard(gameRoomId); return gameRoomId; } diff --git a/src/main/java/janggi/presentation/ui/InputView.java b/src/main/java/janggi/presentation/ui/InputView.java index 53d46f2c4c..7f68f03cf5 100644 --- a/src/main/java/janggi/presentation/ui/InputView.java +++ b/src/main/java/janggi/presentation/ui/InputView.java @@ -14,32 +14,29 @@ public class InputView { Team.CHO, "초" ); - private InputView() { - } - - public static GameCommand chooseNewGame() { + public GameCommand chooseNewGame() { System.out.println("새로운 장기 게임을 시작하시겠습니까?(y,n)"); return GameCommand.from(Console.readLine()); } - public static Long chooseExistsGame() { + public Long chooseExistsGame() { System.out.println("기존 장기 게임방ID를 입력해주세요."); return Long.valueOf(Console.readLine()); } - public static MoveCommand readPoints(Team team) { + public MoveCommand readPoints(Team team) { System.out.println("현재 " + DISPLAY_NAME.get(team) + "나라의 차례입니다."); return new MoveCommand(Parser.parsePoint(readFromPoint()), Parser.parsePoint(readToPoint()) ); } - private static String readFromPoint() { + private String readFromPoint() { System.out.print("움직일 기물의 출발지 좌표 입력해 주세요.(쉼표 기준으로 분리, ex. 0,0) : "); return Console.readLine(); } - private static String readToPoint() { + private String readToPoint() { System.out.print("움직일 기물의 도착지 좌표 입력해 주세요.(쉼표 기준으로 분리, ex. 0,1) : "); return Console.readLine(); } diff --git a/src/main/java/janggi/presentation/ui/OutputView.java b/src/main/java/janggi/presentation/ui/OutputView.java index 6001b3fe2d..a48fa9ad02 100644 --- a/src/main/java/janggi/presentation/ui/OutputView.java +++ b/src/main/java/janggi/presentation/ui/OutputView.java @@ -11,24 +11,24 @@ public class OutputView { Team.CHO, "초" ); - public static void printWinner(Team winner) { + public void printWinner(Team winner) { System.out.println("승자는 " + DISPLAY_NAME.get(winner)); } - public static void printGameStatus(GameStatusInfo status) { + public void printGameStatus(GameStatusInfo status) { status.pieces() .forEach(System.out::println); } - public static void printCurrentScore(double hanScore, double choScore) { + public void printCurrentScore(double hanScore, double choScore) { System.out.printf("한 : %.1f, 초 : %.1f\n", hanScore, choScore); } - public static void printStartGame() { + public void printStartGame() { System.out.println("장기 게임을 시작합니다. 초나라부터 시작하고, 왼쪽 아래를 (0,0)으로 합니다."); } - public static void printError(String message) { + public void printError(String message) { System.out.println(message); } } From 73ba0615519d14d447e9425d4a39f9fe7e0d7508 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 00:33:12 +0900 Subject: [PATCH 067/110] =?UTF-8?q?refactor(Board):=20board=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=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/board/Board.java | 7 +------ .../java/janggi/infra/JdbcBoardRepository.java | 3 +-- .../presentation/JanggiGameController.java | 4 +--- .../java/janggi/domain/board/BoardTest.java | 18 +++++++++--------- src/test/java/janggi/domain/piece/PhoTest.java | 3 +-- .../java/janggi/domain/status/ChoTurnTest.java | 3 +-- .../java/janggi/domain/status/HanTurnTest.java | 6 ++---- 7 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index c86f1d696a..9eadbf2975 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -6,7 +6,6 @@ import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -19,11 +18,7 @@ public class Board { private Map pieces; - public Board() { - this.pieces = new LinkedHashMap<>(); - } - - public void init(Map pieces) { + public Board(Map pieces) { this.pieces = pieces; } diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 650cb0a8c3..9c841233a1 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -85,8 +85,7 @@ public JanggiGame loadGame(Long gameRoomId) { Piece piece = PieceFactory.createPiece(team, type); pieces.put(point, piece); }); - Board board = new Board(); - board.init(pieces); + Board board = new Board(pieces); return new JanggiGame(board, GameStatusFactory.create(Team.valueOf(roomData.currentTurn()))); } catch (SQLException e) { throw new RuntimeException(e); diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index e0c0711d13..9917f4081d 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -65,8 +65,6 @@ private Board readInitBoard() { Map pieces = new LinkedHashMap<>(); List positionInfos = FileParser.readCsvFile("/janggi.csv"); positionInfos.forEach(info -> pieces.put(info.point(), info.piece())); - Board board = new Board(); - board.init(pieces); - return board; + return new Board(pieces); } } diff --git a/src/test/java/janggi/domain/board/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java index 6d1dd9aef4..d0eec89904 100644 --- a/src/test/java/janggi/domain/board/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -16,7 +16,7 @@ class BoardTest { - private final Board board = new Board(); + private Board board; @Test @DisplayName("자신의 기물이 목적지에 있을 경우 예외 발생") @@ -24,7 +24,7 @@ void can_not_move() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(0, 0), new Cha(Team.CHO)); pieces.put(Point.of(0, 1), new Ma(Team.CHO)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(0,0), Point.of(0, 1), Team.CHO)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 도착지에 본인의 기물이 있습니다."); @@ -35,7 +35,7 @@ void can_not_move() { void can_not_move_rule() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(0, 0), new Ma(Team.HAN)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(0, 0), Point.of(1, 1), Team.HAN)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 마가 이동할 수 없는 방향입니다."); @@ -46,7 +46,7 @@ void can_not_move_rule() { void can_not_move_other_piece() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(0, 0), new Jol(Team.CHO)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(0, 0), Point.of(0, 1), Team.HAN)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 상대방의 기물은 움직일 수 없습니다."); @@ -58,7 +58,7 @@ void can_not_move_has_obstacle() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(0, 0), new Sang(Team.CHO)); pieces.put(Point.of(0, 1), new Ma(Team.HAN)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(0, 0), Point.of(2, 3), Team.CHO)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 해당 기물의 이동 경로에 장애물이 있거나 규칙에 어긋납니다."); @@ -71,7 +71,7 @@ void can_not_catch_piece() { pieces.put(Point.of(0, 0), new Pho(Team.CHO)); pieces.put(Point.of(0, 2), new Ma(Team.HAN)); pieces.put(Point.of(0, 4), new Pho(Team.HAN)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(0, 0), Point.of(0, 4), Team.CHO)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 이 기물은 해당 타겟을 잡을 수 없습니다."); @@ -82,7 +82,7 @@ void can_not_catch_piece() { void can_move_pho_diagonal() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(4, 0), new Cha(Team.HAN)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThatThrownBy(() -> board.move(Point.of(4, 0), Point.of(5, 1), Team.HAN)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("[ERROR] 이동할 수 없는 방향입니다."); @@ -94,7 +94,7 @@ void han_total_score() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(0, 0), new Cha(Team.HAN)); pieces.put(Point.of(1, 1), new Pho(Team.HAN)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThat(board.calculateScore(Team.HAN)).isEqualTo(21.5); } @@ -104,7 +104,7 @@ void cho_total_score() { Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(0, 0), new Cha(Team.CHO)); pieces.put(Point.of(1, 1), new Pho(Team.CHO)); - board.init(pieces); + board = new Board(pieces); Assertions.assertThat(board.calculateScore(Team.CHO)).isEqualTo(20); } } diff --git a/src/test/java/janggi/domain/piece/PhoTest.java b/src/test/java/janggi/domain/piece/PhoTest.java index d1f0b42f3f..cafd3bdf99 100644 --- a/src/test/java/janggi/domain/piece/PhoTest.java +++ b/src/test/java/janggi/domain/piece/PhoTest.java @@ -24,14 +24,13 @@ public class PhoTest { @BeforeEach void setUp() { - board = new Board(); Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(1, 1), new Pho(Team.HAN)); pieces.put(Point.of(1, 2), new Cha(Team.HAN)); pieces.put(Point.of(1, 3), new Cha(Team.CHO)); pieces.put(Point.of(1, 5), new Pho(Team.CHO)); pieces.put(Point.of(1, 6), new Pho(Team.CHO)); - board.init(pieces); + board = new Board(pieces); } @ParameterizedTest diff --git a/src/test/java/janggi/domain/status/ChoTurnTest.java b/src/test/java/janggi/domain/status/ChoTurnTest.java index f375472cbb..13a1d2088f 100644 --- a/src/test/java/janggi/domain/status/ChoTurnTest.java +++ b/src/test/java/janggi/domain/status/ChoTurnTest.java @@ -20,13 +20,12 @@ public class ChoTurnTest { @BeforeEach void setUp() { - board = new Board(); Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(4, 1), new Jang(Team.HAN)); pieces.put(Point.of(4, 8), new Jang(Team.CHO)); pieces.put(Point.of(1, 1), new Cha(Team.HAN)); pieces.put(Point.of(2, 3), new Cha(Team.CHO)); - board.init(pieces); + board = new Board(pieces); } @Test diff --git a/src/test/java/janggi/domain/status/HanTurnTest.java b/src/test/java/janggi/domain/status/HanTurnTest.java index c39a7f95c8..5b0b006bde 100644 --- a/src/test/java/janggi/domain/status/HanTurnTest.java +++ b/src/test/java/janggi/domain/status/HanTurnTest.java @@ -20,13 +20,12 @@ public class HanTurnTest { @BeforeEach void setUp() { - board = new Board(); Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(4, 1), new Jang(Team.HAN)); pieces.put(Point.of(4, 8), new Jang(Team.CHO)); pieces.put(Point.of(1, 1), new Cha(Team.HAN)); pieces.put(Point.of(2, 3), new Cha(Team.CHO)); - board.init(pieces); + board = new Board(pieces); } @Test @@ -48,10 +47,9 @@ void turn_change() { @DisplayName("초나라의 기물을 움직일 시 예외 발생") void unavailable_move() { // given - Board board = new Board(); Map pieces = new LinkedHashMap<>(); pieces.put(Point.of(1, 1), new Cha(Team.CHO)); - board.init(pieces); + Board board = new Board(pieces); Point from = Point.of(1, 1); Point to = Point.of(2, 3); From 8359400a356d390953d610209aa7dfea0ab2f133 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 00:40:43 +0900 Subject: [PATCH 068/110] =?UTF-8?q?refactor(PieceData):=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/infra/JdbcBoardRepository.java | 2 +- src/main/java/janggi/infra/dao/PiecesDao.java | 2 +- src/main/java/janggi/infra/dto/PieceData.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 9c841233a1..d7399ee9bb 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -81,7 +81,7 @@ public JanggiGame loadGame(Long gameRoomId) { pieceDatas.forEach(pieceData -> { PieceType type = PieceType.valueOf(pieceData.pieceName()); Team team = Team.valueOf(pieceData.teamName()); - Point point = Point.of(pieceData.col(), pieceData.row()); + Point point = Point.of(pieceData.column(), pieceData.row()); Piece piece = PieceFactory.createPiece(team, type); pieces.put(point, piece); }); diff --git a/src/main/java/janggi/infra/dao/PiecesDao.java b/src/main/java/janggi/infra/dao/PiecesDao.java index 6e7ca4c14f..174e0d1741 100644 --- a/src/main/java/janggi/infra/dao/PiecesDao.java +++ b/src/main/java/janggi/infra/dao/PiecesDao.java @@ -18,7 +18,7 @@ public void save(Long roomId, List data, Connection connection) throw pieceStatement.setString(2, piece.pieceName()); pieceStatement.setString(3, piece.teamName()); pieceStatement.setInt(4, piece.row()); - pieceStatement.setInt(5, piece.col()); + pieceStatement.setInt(5, piece.column()); pieceStatement.executeUpdate(); } } diff --git a/src/main/java/janggi/infra/dto/PieceData.java b/src/main/java/janggi/infra/dto/PieceData.java index 22c96a875c..ff0fc1ec89 100644 --- a/src/main/java/janggi/infra/dto/PieceData.java +++ b/src/main/java/janggi/infra/dto/PieceData.java @@ -4,6 +4,6 @@ public record PieceData( String pieceName, String teamName, int row, - int col + int column ) { } From 36c2748b893a0dd522c1563e2e37ac09b6b9f854 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 00:43:57 +0900 Subject: [PATCH 069/110] =?UTF-8?q?refactor(View):=20view=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?Map=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/presentation/JanggiGameController.java | 3 ++- src/main/java/janggi/presentation/ui/InputView.java | 10 +--------- src/main/java/janggi/presentation/ui/OutputView.java | 4 ++++ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index 9917f4081d..cc3147f8dd 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -43,7 +43,8 @@ public void run() { private void playGame(Long roomId) { try { Team team = service.currentTurn(); - MoveCommand points = inputView.readPoints(team); + outputView.printCurrentTurn(team); + MoveCommand points = inputView.readPoints(); service.play(roomId, points.from(), points.to()); outputView.printGameStatus(service.getBoardStatus()); outputView.printCurrentScore(service.getHanScore(), service.getChoScore()); diff --git a/src/main/java/janggi/presentation/ui/InputView.java b/src/main/java/janggi/presentation/ui/InputView.java index 7f68f03cf5..842794423d 100644 --- a/src/main/java/janggi/presentation/ui/InputView.java +++ b/src/main/java/janggi/presentation/ui/InputView.java @@ -1,19 +1,12 @@ package janggi.presentation.ui; -import janggi.domain.status.Team; import janggi.presentation.dto.GameCommand; import janggi.presentation.dto.MoveCommand; import janggi.presentation.util.Console; import janggi.presentation.util.Parser; -import java.util.Map; public class InputView { - private static final Map DISPLAY_NAME = Map.of( - Team.HAN, "한", - Team.CHO, "초" - ); - public GameCommand chooseNewGame() { System.out.println("새로운 장기 게임을 시작하시겠습니까?(y,n)"); return GameCommand.from(Console.readLine()); @@ -24,8 +17,7 @@ public Long chooseExistsGame() { return Long.valueOf(Console.readLine()); } - public MoveCommand readPoints(Team team) { - System.out.println("현재 " + DISPLAY_NAME.get(team) + "나라의 차례입니다."); + public MoveCommand readPoints() { return new MoveCommand(Parser.parsePoint(readFromPoint()), Parser.parsePoint(readToPoint()) ); diff --git a/src/main/java/janggi/presentation/ui/OutputView.java b/src/main/java/janggi/presentation/ui/OutputView.java index a48fa9ad02..877db204b1 100644 --- a/src/main/java/janggi/presentation/ui/OutputView.java +++ b/src/main/java/janggi/presentation/ui/OutputView.java @@ -11,6 +11,10 @@ public class OutputView { Team.CHO, "초" ); + public void printCurrentTurn(Team team) { + System.out.println("현재 " + DISPLAY_NAME.get(team) + "나라의 차례입니다."); + } + public void printWinner(Team winner) { System.out.println("승자는 " + DISPLAY_NAME.get(winner)); } From 8d2ca5904eb832979c2464e9554df3bb26a2d7c4 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 09:11:46 +0900 Subject: [PATCH 070/110] =?UTF-8?q?refactor(Service):=20=EB=8F=99=EC=8B=9C?= =?UTF-8?q?=EC=84=B1=20=EC=A0=9C=EC=96=B4=EB=A5=BC=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?Map=EC=9C=BC=EB=A1=9C=20=ED=95=84=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/application/JanggiGameService.java | 38 +++++++++++-------- .../presentation/JanggiGameController.java | 14 +++---- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index c167203676..b3f44c6f84 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -7,51 +7,57 @@ import janggi.domain.status.ChoTurn; import janggi.domain.status.Team; import janggi.presentation.dto.GameStatusInfo; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class JanggiGameService { private final BoardRepository repository; - private JanggiGame game; + private final Map games; public JanggiGameService(BoardRepository repository) { this.repository = repository; + this.games = new ConcurrentHashMap<>(); } public Long startNewGame(Board initBoard) { - this.game = new JanggiGame(initBoard, new ChoTurn()); - return repository.save(this.game); + JanggiGame game = new JanggiGame(initBoard, new ChoTurn()); + Long roomId = repository.save(game); + games.put(roomId, game); + return roomId; } public void loadExistsBoard(Long gameRoomId) { - this.game = repository.loadGame(gameRoomId); + this.games.put(gameRoomId, repository.loadGame(gameRoomId)); } - public GameStatusInfo getBoardStatus() { - return GameStatusInfo.from(game.getBoardStatus()); + public GameStatusInfo getBoardStatus(Long gameRoomId) { + return GameStatusInfo.from(games.get(gameRoomId).getBoardStatus()); } - public boolean isFinished() { - return game.isFinished(); + public boolean isFinished(Long gameRoomId) { + return games.get(gameRoomId).isFinished(); } public void play(Long roomId, Point from, Point to) { + JanggiGame game = games.get(roomId); game.play(from, to); repository.update(roomId, from, to, game); } - public Team winner() { - return game.getWinner(); + public Team winner(Long roomId) { + return games.get(roomId).getWinner(); } - public Team currentTurn() { - return game.getTeam(); + public Team currentTurn(Long roomId) { + return games.get(roomId).getTeam(); } - public double getHanScore() { - return game.getHanScore(); + public double getHanScore(Long roomId) { + return games.get(roomId).getHanScore(); } - public double getChoScore() { - return game.getChoScore(); + public double getChoScore(Long roomId) { + return games.get(roomId).getChoScore(); } } diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index cc3147f8dd..c326b4833d 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -31,23 +31,23 @@ public JanggiGameController(JanggiGameService service, InputView inputView, Outp public void run() { Long roomId = chooseBoard(inputView.chooseNewGame()); outputView.printStartGame(); - outputView.printGameStatus(service.getBoardStatus()); - outputView.printCurrentScore(service.getHanScore(), service.getChoScore()); - while (!service.isFinished()) { + outputView.printGameStatus(service.getBoardStatus(roomId)); + outputView.printCurrentScore(service.getHanScore(roomId), service.getChoScore(roomId)); + while (!service.isFinished(roomId)) { playGame(roomId); } - outputView.printWinner(service.winner()); + outputView.printWinner(service.winner(roomId)); Console.close(); } private void playGame(Long roomId) { try { - Team team = service.currentTurn(); + Team team = service.currentTurn(roomId); outputView.printCurrentTurn(team); MoveCommand points = inputView.readPoints(); service.play(roomId, points.from(), points.to()); - outputView.printGameStatus(service.getBoardStatus()); - outputView.printCurrentScore(service.getHanScore(), service.getChoScore()); + outputView.printGameStatus(service.getBoardStatus(roomId)); + outputView.printCurrentScore(service.getHanScore(roomId), service.getChoScore(roomId)); } catch (IllegalArgumentException e) { outputView.printError(e.getMessage()); } From c404444f3dc7cbf3b47f45365395971bb86ac990 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 09:22:07 +0900 Subject: [PATCH 071/110] =?UTF-8?q?refactor(Repository):=20nullable?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/BoardRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/board/BoardRepository.java b/src/main/java/janggi/domain/board/BoardRepository.java index 9d15a743d1..886c8fb635 100644 --- a/src/main/java/janggi/domain/board/BoardRepository.java +++ b/src/main/java/janggi/domain/board/BoardRepository.java @@ -4,7 +4,7 @@ import janggi.domain.point.Point; public interface BoardRepository { - Long save(JanggiGame game); + long save(JanggiGame game); void update(Long roomId, Point from, Point to, JanggiGame game); JanggiGame loadGame(Long gameRoomId); } From 0029a5a7084d6f4c185880e3908fdf0c35ab4c97 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 09:22:32 +0900 Subject: [PATCH 072/110] =?UTF-8?q?refactor(Repository):=20=EC=BB=A4?= =?UTF-8?q?=EB=84=A5=EC=85=98=ED=92=80=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/infra/JdbcBoardRepository.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index d7399ee9bb..4128b73ef8 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -16,16 +16,19 @@ import java.io.IOException; import java.io.InputStream; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import org.h2.jdbcx.JdbcConnectionPool; public class JdbcBoardRepository implements BoardRepository { + private static final int POOL_SIZE = 10; + + private final JdbcConnectionPool connectionPool; private final GameRoomDao roomDao = new GameRoomDao(); private final PiecesDao piecesDao = new PiecesDao(); private final String url; @@ -40,13 +43,15 @@ public JdbcBoardRepository() { url = properties.getProperty("db.url"); username = properties.getProperty("db.username"); password = properties.getProperty("db.password"); + connectionPool = JdbcConnectionPool.create(url, username, password); + connectionPool.setMaxConnections(POOL_SIZE); } catch (IOException e) { throw new RuntimeException(e); } } @Override - public Long save(JanggiGame game) { + public long save(JanggiGame game) { try (Connection connection = getConnection()) { Long roomId = roomDao.save(GameRoomData.from(game), connection); List> pieces = game.getBoardStatus(); @@ -93,7 +98,7 @@ public JanggiGame loadGame(Long gameRoomId) { } private Connection getConnection() throws SQLException { - return DriverManager.getConnection(url, username, password); + return connectionPool.getConnection(); } private static void addPieceData(List> pieces, int i, List data) { From 825229e37b7726cdcbc1c9b34f85043d5372aa04 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 09:23:01 +0900 Subject: [PATCH 073/110] =?UTF-8?q?refactor(Service):=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=EB=B0=A9=20ID=20=EA=B2=80=EC=A6=9D=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/JanggiGameService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index b3f44c6f84..9a0a082f2a 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -28,6 +28,9 @@ public Long startNewGame(Board initBoard) { } public void loadExistsBoard(Long gameRoomId) { + if(gameRoomId == null) { + throw new IllegalArgumentException("[ERROR] 잘못된 게임방 ID 입력입니다."); + } this.games.put(gameRoomId, repository.loadGame(gameRoomId)); } From 5f46ac9cdef05caae5c8c7e31d31f6a63ce3d250 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 09:30:10 +0900 Subject: [PATCH 074/110] =?UTF-8?q?refactor(Repository):=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=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/infra/JdbcBoardRepository.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 4128b73ef8..a4d640bc86 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -53,6 +53,7 @@ public JdbcBoardRepository() { @Override public long save(JanggiGame game) { try (Connection connection = getConnection()) { + connection.setAutoCommit(false); Long roomId = roomDao.save(GameRoomData.from(game), connection); List> pieces = game.getBoardStatus(); List data = new ArrayList<>(); @@ -60,6 +61,7 @@ public long save(JanggiGame game) { addPieceData(pieces, i, data); } piecesDao.save(roomId, data, connection); + connection.commit(); return roomId; } catch (SQLException e) { throw new RuntimeException(e); @@ -69,9 +71,11 @@ public long save(JanggiGame game) { @Override public void update(Long roomId, Point from, Point to, JanggiGame game) { try (Connection connection = getConnection()) { + connection.setAutoCommit(false); roomDao.update(roomId, GameRoomData.from(game), connection); piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); + connection.commit(); } catch (SQLException e) { throw new RuntimeException(e); } @@ -80,6 +84,7 @@ public void update(Long roomId, Point from, Point to, JanggiGame game) { @Override public JanggiGame loadGame(Long gameRoomId) { try (Connection connection = getConnection()) { + connection.setAutoCommit(false); GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection); List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); Map pieces = new LinkedHashMap<>(); @@ -91,6 +96,7 @@ public JanggiGame loadGame(Long gameRoomId) { pieces.put(point, piece); }); Board board = new Board(pieces); + connection.commit(); return new JanggiGame(board, GameStatusFactory.create(Team.valueOf(roomData.currentTurn()))); } catch (SQLException e) { throw new RuntimeException(e); From 6cb316d30090fc03c6e68588cf810d895d7eb12f Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 10:54:17 +0900 Subject: [PATCH 075/110] =?UTF-8?q?refactor(Repository):=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=20=ED=85=9C=ED=94=8C=EB=A6=BF=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/infra/JdbcBoardRepository.java | 48 ++++++++++++------- .../janggi/infra/TransactionCallback.java | 9 ++++ 2 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 src/main/java/janggi/infra/TransactionCallback.java diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index a4d640bc86..b78d1a1395 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -52,39 +52,31 @@ public JdbcBoardRepository() { @Override public long save(JanggiGame game) { - try (Connection connection = getConnection()) { - connection.setAutoCommit(false); - Long roomId = roomDao.save(GameRoomData.from(game), connection); + return executeInTransaction(connection -> { + long roomId = roomDao.save(GameRoomData.from(game), connection); List> pieces = game.getBoardStatus(); List data = new ArrayList<>(); for (int i = 0; i < pieces.size(); i++) { addPieceData(pieces, i, data); } piecesDao.save(roomId, data, connection); - connection.commit(); return roomId; - } catch (SQLException e) { - throw new RuntimeException(e); - } + }); } @Override public void update(Long roomId, Point from, Point to, JanggiGame game) { - try (Connection connection = getConnection()) { - connection.setAutoCommit(false); + executeInTransaction(connection -> { roomDao.update(roomId, GameRoomData.from(game), connection); piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); - connection.commit(); - } catch (SQLException e) { - throw new RuntimeException(e); - } + return null; + }); } @Override public JanggiGame loadGame(Long gameRoomId) { - try (Connection connection = getConnection()) { - connection.setAutoCommit(false); + return executeInTransaction(connection -> { GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection); List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); Map pieces = new LinkedHashMap<>(); @@ -98,9 +90,7 @@ public JanggiGame loadGame(Long gameRoomId) { Board board = new Board(pieces); connection.commit(); return new JanggiGame(board, GameStatusFactory.create(Team.valueOf(roomData.currentTurn()))); - } catch (SQLException e) { - throw new RuntimeException(e); - } + }); } private Connection getConnection() throws SQLException { @@ -117,4 +107,26 @@ private static void addPieceData(List> pieces, int i, List T executeInTransaction(TransactionCallback action) { + try (Connection connection = getConnection()) { + return processTransaction(connection, action); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] DB 커넥션 에러", e); + } + } + + private T processTransaction(Connection connection, TransactionCallback action) throws SQLException { + try { + connection.setAutoCommit(false); + T result = action.doInTransaction(connection); + connection.commit(); + return result; + } catch (SQLException e) { + connection.rollback(); + throw new RuntimeException("[ERROR] 게임 저장 중 트랜잭션 롤백됨", e); + } finally { + connection.setAutoCommit(true); + } + } } diff --git a/src/main/java/janggi/infra/TransactionCallback.java b/src/main/java/janggi/infra/TransactionCallback.java new file mode 100644 index 0000000000..a91e87b029 --- /dev/null +++ b/src/main/java/janggi/infra/TransactionCallback.java @@ -0,0 +1,9 @@ +package janggi.infra; + +import java.sql.Connection; +import java.sql.SQLException; + +@FunctionalInterface +public interface TransactionCallback { + T doInTransaction(Connection connection) throws SQLException; +} From ce5ea69b3e3a79d31e6c3b262d01375ac89020e1 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 11:12:14 +0900 Subject: [PATCH 076/110] =?UTF-8?q?refactor(Controller):=20primitive=20typ?= =?UTF-8?q?e=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20roomId?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/JanggiGameController.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index c326b4833d..38ade64ab9 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -29,7 +29,7 @@ public JanggiGameController(JanggiGameService service, InputView inputView, Outp } public void run() { - Long roomId = chooseBoard(inputView.chooseNewGame()); + long roomId = chooseBoard(inputView.chooseNewGame()); outputView.printStartGame(); outputView.printGameStatus(service.getBoardStatus(roomId)); outputView.printCurrentScore(service.getHanScore(roomId), service.getChoScore(roomId)); @@ -53,13 +53,14 @@ private void playGame(Long roomId) { } } - private Long chooseBoard(GameCommand command) { + private long chooseBoard(GameCommand command) { if (command.isNewGame()) { return service.startNewGame(readInitBoard()); } - Long gameRoomId = inputView.chooseExistsGame(); - service.loadExistsBoard(gameRoomId); - return gameRoomId; + Long roomId = inputView.chooseExistsGame(); + validateIsNull(roomId); + service.loadExistsBoard(roomId); + return roomId; } private Board readInitBoard() { @@ -68,4 +69,10 @@ private Board readInitBoard() { positionInfos.forEach(info -> pieces.put(info.point(), info.piece())); return new Board(pieces); } + + private void validateIsNull(Long roomId) { + if(roomId == null) { + throw new IllegalArgumentException("[ERROR] 잘못된 게임방 ID 입력입니다."); + } + } } From c631ad5ed7cddd55e05d725eef3f4a1ba91a609b Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 11:13:13 +0900 Subject: [PATCH 077/110] =?UTF-8?q?refactor(Service):=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20primitive=20type=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/application/JanggiGameService.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index 9a0a082f2a..9b541e3c1b 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -20,26 +20,23 @@ public JanggiGameService(BoardRepository repository) { this.games = new ConcurrentHashMap<>(); } - public Long startNewGame(Board initBoard) { + public long startNewGame(Board initBoard) { JanggiGame game = new JanggiGame(initBoard, new ChoTurn()); - Long roomId = repository.save(game); + long roomId = repository.save(game); games.put(roomId, game); return roomId; } - public void loadExistsBoard(Long gameRoomId) { - if(gameRoomId == null) { - throw new IllegalArgumentException("[ERROR] 잘못된 게임방 ID 입력입니다."); - } - this.games.put(gameRoomId, repository.loadGame(gameRoomId)); + public void loadExistsBoard(Long roomId) { + this.games.put(roomId, repository.loadGame(roomId)); } - public GameStatusInfo getBoardStatus(Long gameRoomId) { - return GameStatusInfo.from(games.get(gameRoomId).getBoardStatus()); + public GameStatusInfo getBoardStatus(Long roomId) { + return GameStatusInfo.from(games.get(roomId).getBoardStatus()); } - public boolean isFinished(Long gameRoomId) { - return games.get(gameRoomId).isFinished(); + public boolean isFinished(Long roomId) { + return games.get(roomId).isFinished(); } public void play(Long roomId, Point from, Point to) { From 24c9daa364fa83e5946c7d53514140501d0ae583 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 11:39:17 +0900 Subject: [PATCH 078/110] =?UTF-8?q?refactor(Piece):=20getTeam()=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/piece/Implementation/Jol.java | 5 +++++ src/main/java/janggi/domain/piece/Piece.java | 1 + .../domain/piece/template/AbstractFixedStepPiece.java | 10 ++++++++++ .../domain/piece/template/AbstractNormalPiece.java | 5 +++++ .../domain/piece/template/AbstractStraightPiece.java | 5 +++++ src/main/java/janggi/infra/JdbcBoardRepository.java | 3 +-- 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Implementation/Jol.java b/src/main/java/janggi/domain/piece/Implementation/Jol.java index 47a8876baf..bb0f484b70 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Jol.java +++ b/src/main/java/janggi/domain/piece/Implementation/Jol.java @@ -63,6 +63,11 @@ public PieceType getType() { return type; } + @Override + public Team getTeam() { + return team; + } + @Override public int getScore() { return SCORE; diff --git a/src/main/java/janggi/domain/piece/Piece.java b/src/main/java/janggi/domain/piece/Piece.java index fe677a6880..22f8147571 100644 --- a/src/main/java/janggi/domain/piece/Piece.java +++ b/src/main/java/janggi/domain/piece/Piece.java @@ -11,6 +11,7 @@ public interface Piece { boolean isSameType(PieceType type); Points getRoutePoints(Point from, Point to); PieceType getType(); + Team getTeam(); int getScore(); default boolean canCapture(Piece piece) { diff --git a/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java b/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java index 1db5d80dca..77fe346f6e 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java @@ -22,22 +22,32 @@ public AbstractFixedStepPiece(int score, Team team, PieceType type) { @Override public abstract Points getRoutePoints(Point from, Point to); + @Override public boolean canMove(Route route) { return route.isEmpty(); } + @Override public boolean isSameTeam(Team team) { return this.team.equals(team); } + @Override public boolean isSameType(PieceType type) { return this.type.equals(type); } + @Override public PieceType getType() { return type; } + @Override + public Team getTeam() { + return team; + } + + @Override public int getScore() { return score; } diff --git a/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java index 9dfcfe7218..0a279ca815 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java @@ -65,6 +65,11 @@ public int getScore() { return score; } + @Override + public Team getTeam() { + return team; + } + private void validateDistance(int distanceCol, int distanceRow) { if (distanceCol > MAX_DISTANCE || distanceRow > MAX_DISTANCE || (distanceCol == 0 && distanceRow == 0)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); diff --git a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java index 5b31c119f6..a359342e24 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java @@ -67,6 +67,11 @@ public int getScore() { return score; } + @Override + public Team getTeam() { + return team; + } + private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { if (from.inSameCastle(to)) { CastleDirection.find(from, signCol, signRow); diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index b78d1a1395..ac7512d20e 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -103,8 +103,7 @@ private static void addPieceData(List> pieces, int i, List Date: Fri, 3 Apr 2026 13:24:44 +0900 Subject: [PATCH 079/110] =?UTF-8?q?refactor(Service):=20=EB=8F=99=EC=8B=9C?= =?UTF-8?q?=EC=84=B1=20=EC=A0=9C=EC=96=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/application/JanggiGameService.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index 9b541e3c1b..5d95bd10e3 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -7,57 +7,56 @@ import janggi.domain.status.ChoTurn; import janggi.domain.status.Team; import janggi.presentation.dto.GameStatusInfo; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class JanggiGameService { private final BoardRepository repository; - private final Map games; public JanggiGameService(BoardRepository repository) { this.repository = repository; - this.games = new ConcurrentHashMap<>(); } public long startNewGame(Board initBoard) { JanggiGame game = new JanggiGame(initBoard, new ChoTurn()); - long roomId = repository.save(game); - games.put(roomId, game); - return roomId; + return repository.save(game); } public void loadExistsBoard(Long roomId) { - this.games.put(roomId, repository.loadGame(roomId)); + repository.loadGame(roomId); } public GameStatusInfo getBoardStatus(Long roomId) { - return GameStatusInfo.from(games.get(roomId).getBoardStatus()); + return GameStatusInfo.from(repository.loadGame(roomId).getBoardStatus()); } public boolean isFinished(Long roomId) { - return games.get(roomId).isFinished(); + return repository.loadGame(roomId) + .isFinished(); } public void play(Long roomId, Point from, Point to) { - JanggiGame game = games.get(roomId); + JanggiGame game = repository.loadGame(roomId); game.play(from, to); repository.update(roomId, from, to, game); } public Team winner(Long roomId) { - return games.get(roomId).getWinner(); + return repository.loadGame(roomId) + .getWinner(); } public Team currentTurn(Long roomId) { - return games.get(roomId).getTeam(); + return repository.loadGame(roomId) + .getTeam(); } public double getHanScore(Long roomId) { - return games.get(roomId).getHanScore(); + return repository.loadGame(roomId) + .getHanScore(); } public double getChoScore(Long roomId) { - return games.get(roomId).getChoScore(); + return repository.loadGame(roomId) + .getChoScore(); } } From b04d73e398e75348ec82746592eee758b5af1994 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 13:58:40 +0900 Subject: [PATCH 080/110] =?UTF-8?q?refactor(Repository):=20DB=20=EC=BB=A4?= =?UTF-8?q?=EB=84=A5=EC=85=98=20=EA=B4=80=EB=A6=AC=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20roomId=20=EA=B2=80=EC=A6=9D=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 4 ++- .../janggi/infra/DataConnectionManager.java | 34 +++++++++++++++++++ .../presentation/JanggiGameController.java | 7 ---- 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 src/main/java/janggi/infra/DataConnectionManager.java diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index 6c3a0648bc..70a7d8b06e 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -2,6 +2,7 @@ import janggi.application.JanggiGameService; import janggi.domain.board.BoardRepository; +import janggi.infra.DataConnectionManager; import janggi.infra.JdbcBoardRepository; import janggi.presentation.JanggiGameController; import janggi.presentation.ui.InputView; @@ -12,7 +13,8 @@ public class JanggiApplication { public static void main(String[] args) throws SQLException { Server server = Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start(); - BoardRepository repository = new JdbcBoardRepository(); + DataConnectionManager manager = new DataConnectionManager(); + BoardRepository repository = new JdbcBoardRepository(manager); JanggiGameService service = new JanggiGameService(repository); InputView inputView = new InputView(); OutputView outputView = new OutputView(); diff --git a/src/main/java/janggi/infra/DataConnectionManager.java b/src/main/java/janggi/infra/DataConnectionManager.java new file mode 100644 index 0000000000..6a048edb70 --- /dev/null +++ b/src/main/java/janggi/infra/DataConnectionManager.java @@ -0,0 +1,34 @@ +package janggi.infra; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import org.h2.jdbcx.JdbcConnectionPool; + +public class DataConnectionManager { + + private static final int POOL_SIZE = 10; + + private final JdbcConnectionPool connectionPool; + + public DataConnectionManager() { + try { + Properties properties = new Properties(); + InputStream inputStream = getClass().getClassLoader().getResourceAsStream("application.properties"); + properties.load(inputStream); + String url = properties.getProperty("db.url"); + String username = properties.getProperty("db.username"); + String password = properties.getProperty("db.password"); + connectionPool = JdbcConnectionPool.create(url, username, password); + connectionPool.setMaxConnections(POOL_SIZE); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Connection getConnection() throws SQLException { + return connectionPool.getConnection(); + } +} diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index 38ade64ab9..c608f69da0 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -58,7 +58,6 @@ private long chooseBoard(GameCommand command) { return service.startNewGame(readInitBoard()); } Long roomId = inputView.chooseExistsGame(); - validateIsNull(roomId); service.loadExistsBoard(roomId); return roomId; } @@ -69,10 +68,4 @@ private Board readInitBoard() { positionInfos.forEach(info -> pieces.put(info.point(), info.piece())); return new Board(pieces); } - - private void validateIsNull(Long roomId) { - if(roomId == null) { - throw new IllegalArgumentException("[ERROR] 잘못된 게임방 ID 입력입니다."); - } - } } From 315983e790aa56e4cb1ea6f8c6d14f8dba59bae0 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 13:58:46 +0900 Subject: [PATCH 081/110] =?UTF-8?q?refactor(Repository):=20DB=20=EC=BB=A4?= =?UTF-8?q?=EB=84=A5=EC=85=98=20=EA=B4=80=EB=A6=AC=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20roomId=20=EA=B2=80=EC=A6=9D=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/infra/JdbcBoardRepository.java | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index ac7512d20e..e3895f2ad2 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -13,41 +13,22 @@ import janggi.infra.dao.PiecesDao; import janggi.infra.dto.GameRoomData; import janggi.infra.dto.PieceData; -import java.io.IOException; -import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Properties; -import org.h2.jdbcx.JdbcConnectionPool; public class JdbcBoardRepository implements BoardRepository { - private static final int POOL_SIZE = 10; - - private final JdbcConnectionPool connectionPool; + private final DataConnectionManager manager; private final GameRoomDao roomDao = new GameRoomDao(); private final PiecesDao piecesDao = new PiecesDao(); - private final String url; - private final String username; - private final String password; - public JdbcBoardRepository() { - try { - Properties properties = new Properties(); - InputStream inputStream = getClass().getClassLoader().getResourceAsStream("application.properties"); - properties.load(inputStream); - url = properties.getProperty("db.url"); - username = properties.getProperty("db.username"); - password = properties.getProperty("db.password"); - connectionPool = JdbcConnectionPool.create(url, username, password); - connectionPool.setMaxConnections(POOL_SIZE); - } catch (IOException e) { - throw new RuntimeException(e); - } + + public JdbcBoardRepository(DataConnectionManager manager) { + this.manager = manager; } @Override @@ -76,6 +57,7 @@ public void update(Long roomId, Point from, Point to, JanggiGame game) { @Override public JanggiGame loadGame(Long gameRoomId) { + validateIsNull(gameRoomId); return executeInTransaction(connection -> { GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection); List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); @@ -93,10 +75,6 @@ public JanggiGame loadGame(Long gameRoomId) { }); } - private Connection getConnection() throws SQLException { - return connectionPool.getConnection(); - } - private static void addPieceData(List> pieces, int i, List data) { for (int j = 0; j < pieces.get(i).size(); j++) { Piece piece = pieces.get(i).get(j); @@ -108,7 +86,7 @@ private static void addPieceData(List> pieces, int i, List T executeInTransaction(TransactionCallback action) { - try (Connection connection = getConnection()) { + try (Connection connection = manager.getConnection()) { return processTransaction(connection, action); } catch (SQLException e) { throw new RuntimeException("[ERROR] DB 커넥션 에러", e); @@ -128,4 +106,10 @@ private T processTransaction(Connection connection, TransactionCallback a connection.setAutoCommit(true); } } + + private void validateIsNull(Long roomId) { + if(roomId == null) { + throw new IllegalArgumentException("[ERROR] 잘못된 게임방 ID 입력입니다."); + } + } } From f4419bbd0cff71d181660ac23124e2e067e73715 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 14:11:22 +0900 Subject: [PATCH 082/110] =?UTF-8?q?refactor(Controller):=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=EC=97=86=EC=96=B4=EC=A7=84=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/application/JanggiGameService.java | 4 ---- src/main/java/janggi/presentation/JanggiGameController.java | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index 5d95bd10e3..103185ab15 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -21,10 +21,6 @@ public long startNewGame(Board initBoard) { return repository.save(game); } - public void loadExistsBoard(Long roomId) { - repository.loadGame(roomId); - } - public GameStatusInfo getBoardStatus(Long roomId) { return GameStatusInfo.from(repository.loadGame(roomId).getBoardStatus()); } diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index c608f69da0..56b22f9705 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -57,9 +57,7 @@ private long chooseBoard(GameCommand command) { if (command.isNewGame()) { return service.startNewGame(readInitBoard()); } - Long roomId = inputView.chooseExistsGame(); - service.loadExistsBoard(roomId); - return roomId; + return inputView.chooseExistsGame(); } private Board readInitBoard() { From 41a7302ba5e10f5589c61f24ea00e299e7aeae10 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 14:39:25 +0900 Subject: [PATCH 083/110] =?UTF-8?q?refactor(init):=20unique=20=EC=A0=9C?= =?UTF-8?q?=EC=95=BD=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/init.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql index 017a0e3dc4..a81672f8ff 100644 --- a/src/main/resources/init.sql +++ b/src/main/resources/init.sql @@ -12,5 +12,6 @@ CREATE TABLE IF NOT EXISTS piece( team VARCHAR(10) NOT NULL, row_pos INT NOT NULL, col_pos INT NOT NULL, - FOREIGN KEY (game_room_id) REFERENCES game_room(id) ON DELETE CASCADE + FOREIGN KEY (game_room_id) REFERENCES game_room(id) ON DELETE CASCADE, + UNIQUE (game_room_id, row_pos, col_pos) ); From dfd5eb31d78c9f849a58a71132a4ad0b22f3ae59 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:06:35 +0900 Subject: [PATCH 084/110] =?UTF-8?q?refactor(Board):=20=EA=B0=80=EC=82=B0?= =?UTF-8?q?=EC=A0=90=20=EA=B3=84=EC=82=B0=20=EC=B1=85=EC=9E=84=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/JanggiGame.java | 3 ++- src/main/java/janggi/domain/board/Board.java | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/janggi/domain/JanggiGame.java b/src/main/java/janggi/domain/JanggiGame.java index b16d3508c2..5042c1b2a0 100644 --- a/src/main/java/janggi/domain/JanggiGame.java +++ b/src/main/java/janggi/domain/JanggiGame.java @@ -9,6 +9,7 @@ public class JanggiGame { + private static final double BONUS_SCORE = 1.5; private final Board board; private GameStatus gameStatus; @@ -45,6 +46,6 @@ public double getChoScore() { } public double getHanScore() { - return board.calculateScore(Team.HAN); + return board.calculateScore(Team.HAN) + BONUS_SCORE; } } diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 9eadbf2975..7d8c568d30 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -54,15 +54,11 @@ public List> getPieces() { } public double calculateScore(Team team) { - int sum = pieces.values() + return pieces.values() .stream() .filter(piece -> piece.isSameTeam(team)) .mapToInt(Piece::getScore) .sum(); - if (team.equals(Team.HAN)) { - return sum + 1.5; - } - return sum; } public Route getRoute(Points points) { From 8f1c77a5d5445fe714d73e294499ddcf9747d98e Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:07:05 +0900 Subject: [PATCH 085/110] =?UTF-8?q?refactor(GameRoom):=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/infra/dao/GameRoomDao.java | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/src/main/java/janggi/infra/dao/GameRoomDao.java b/src/main/java/janggi/infra/dao/GameRoomDao.java index 4e9297bf8c..a4d0f784a9 100644 --- a/src/main/java/janggi/infra/dao/GameRoomDao.java +++ b/src/main/java/janggi/infra/dao/GameRoomDao.java @@ -6,49 +6,58 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.Optional; public class GameRoomDao { - public Long save(GameRoomData data, Connection connection) throws SQLException { + public Long save(GameRoomData data, Connection connection) { String sql = "INSERT INTO game_room (current_turn, winner, cha_score, han_score) VALUES (?, ?, ?, ?)"; - PreparedStatement roomStatement = connection.prepareStatement(sql, - Statement.RETURN_GENERATED_KEYS); - roomStatement.setString(1, data.currentTurn()); - roomStatement.setString(2, data.winner()); - roomStatement.setDouble(3, data.choScore()); - roomStatement.setDouble(4, data.hanScore()); - roomStatement.executeUpdate(); - ResultSet resultSet = roomStatement.getGeneratedKeys(); - if (!resultSet.next()) { - throw new SQLException("[ERROR] 게임 보드 생성 실패"); + try(PreparedStatement roomStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + roomStatement.setString(1, data.currentTurn()); + roomStatement.setString(2, data.winner()); + roomStatement.setDouble(3, data.choScore()); + roomStatement.setDouble(4, data.hanScore()); + roomStatement.executeUpdate(); + ResultSet resultSet = roomStatement.getGeneratedKeys(); + if (!resultSet.next()) { + throw new SQLException("[ERROR] 게임 보드 생성 실패"); + } + return resultSet.getLong(1); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] 게임 방 데이터를 DB에 저장하는 중 오류가 발생했습니다.", e); } - return resultSet.getLong(1); } - public void update(Long roomId, GameRoomData data, Connection connection) throws SQLException { + public void update(Long roomId, GameRoomData data, Connection connection) { String sql = "UPDATE game_room SET current_turn = ?, winner = ?, cha_score = ?, han_score = ? WHERE id = ?"; - PreparedStatement roomStatement = connection.prepareStatement(sql); - roomStatement.setString(1, data.currentTurn()); - roomStatement.setString(2, data.winner()); - roomStatement.setDouble(3, data.choScore()); - roomStatement.setDouble(4, data.hanScore()); - roomStatement.setLong(5, roomId); - roomStatement.executeUpdate(); + try (PreparedStatement roomStatement = connection.prepareStatement(sql)) { + roomStatement.setString(1, data.currentTurn()); + roomStatement.setString(2, data.winner()); + roomStatement.setDouble(3, data.choScore()); + roomStatement.setDouble(4, data.hanScore()); + roomStatement.setLong(5, roomId); + roomStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] 기물 이동 위치를 DB에 저장하는 중 오류가 발생했습니다.", e); + } } - public GameRoomData findRoomById(Long roomId, Connection connection) throws SQLException { + public Optional findRoomById(Long roomId, Connection connection) { String sql = "SELECT current_turn, winner, cha_score, han_score FROM game_room WHERE id=?"; - PreparedStatement roomStatement = connection.prepareStatement(sql); - roomStatement.setLong(1, roomId); - ResultSet resultSet = roomStatement.executeQuery(); - if (resultSet.next()) { - return new GameRoomData( - resultSet.getString("current_turn"), - resultSet.getString("winner"), - resultSet.getDouble("cha_score"), - resultSet.getDouble("han_score") - ); + try (PreparedStatement roomStatement = connection.prepareStatement(sql)) { + roomStatement.setLong(1, roomId); + ResultSet resultSet = roomStatement.executeQuery(); + if (resultSet.next()) { + return Optional.of(new GameRoomData( + resultSet.getString("current_turn"), + resultSet.getString("winner"), + resultSet.getDouble("cha_score"), + resultSet.getDouble("han_score") + )); + } + return Optional.empty(); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] 해당 방을 DB에서 조회하는 중 오류가 발생했습니다.", e); } - throw new IllegalArgumentException("[ERROR] 해당 방이 존재하지 않습니다."); } } From 252829da088fc098bfc28e5b5b608045f61e20e2 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:07:22 +0900 Subject: [PATCH 086/110] =?UTF-8?q?refactor(Repository):=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/infra/JdbcBoardRepository.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index e3895f2ad2..2ec55ae7f4 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -19,6 +19,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; public class JdbcBoardRepository implements BoardRepository { @@ -51,7 +52,7 @@ public void update(Long roomId, Point from, Point to, JanggiGame game) { roomDao.update(roomId, GameRoomData.from(game), connection); piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); - return null; + return Optional.empty(); }); } @@ -59,7 +60,8 @@ public void update(Long roomId, Point from, Point to, JanggiGame game) { public JanggiGame loadGame(Long gameRoomId) { validateIsNull(gameRoomId); return executeInTransaction(connection -> { - GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection); + GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection) + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 존재하지 않는 게임방 입니다.")); List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); Map pieces = new LinkedHashMap<>(); pieceDatas.forEach(pieceData -> { From 8bdf44d09ca950d2643454fd7321dbba02447751 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:45:02 +0900 Subject: [PATCH 087/110] =?UTF-8?q?refactor(Castle):=20=EA=B6=81=EC=84=B1?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Castle.java | 27 +++++++++++++++++++ .../domain/piece/Implementation/Jol.java | 5 ++-- .../piece/template/AbstractNormalPiece.java | 3 ++- .../piece/template/AbstractStraightPiece.java | 3 ++- src/main/java/janggi/domain/point/Point.java | 20 +------------- 5 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 src/main/java/janggi/domain/board/Castle.java diff --git a/src/main/java/janggi/domain/board/Castle.java b/src/main/java/janggi/domain/board/Castle.java new file mode 100644 index 0000000000..8fd361fde1 --- /dev/null +++ b/src/main/java/janggi/domain/board/Castle.java @@ -0,0 +1,27 @@ +package janggi.domain.board; + +import janggi.domain.point.Point; + +public class Castle { + + private static final int HAN_CASTLE_ZONE_ROW_MIN = 7; + private static final int HAN_CASTLE_ZONE_ROW_MAX = 9; + private static final int CHO_CASTLE_ZONE_ROW_MIN =0; + private static final int CHO_CASTLE_ZONE_ROW_MAX =2; + private static final int CASTLE_ZONE_COLUMN_MIN = 3; + private static final int CASTLE_ZONE_COLUMN_MAX = 5; + + public static boolean inSameCastle(Point to, Point from) { + if (isCastle(from.getColumn(), from.getRow()) && isCastle(to.getColumn(), to.getRow())) { + return (from.getRow() <= CHO_CASTLE_ZONE_ROW_MAX) == (to.getRow() <= CHO_CASTLE_ZONE_ROW_MAX); + } + return false; + } + + private static boolean isCastle(int column, int row) { + boolean isColumnCastle = column >= CASTLE_ZONE_COLUMN_MIN && column <= CASTLE_ZONE_COLUMN_MAX; + boolean isRowHanCastle = row >= HAN_CASTLE_ZONE_ROW_MIN && row <= HAN_CASTLE_ZONE_ROW_MAX; + boolean isRowChoCastle = row <= CHO_CASTLE_ZONE_ROW_MAX && row >= CHO_CASTLE_ZONE_ROW_MIN; + return isColumnCastle && (isRowHanCastle || isRowChoCastle); + } +} diff --git a/src/main/java/janggi/domain/piece/Implementation/Jol.java b/src/main/java/janggi/domain/piece/Implementation/Jol.java index bb0f484b70..574128df17 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Jol.java +++ b/src/main/java/janggi/domain/piece/Implementation/Jol.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.board.Castle; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.CastleDirection; @@ -33,7 +34,7 @@ public Points getRoutePoints(Point from, Point to) { validateForward(signRow); int distanceCol = abs(pathCol); int distanceRow = abs(pathRow); - if (from.inSameCastle(to)) { + if (Castle.inSameCastle(from, to)) { CastleDirection direction = CastleDirection.find(from, signCol, signRow); Point point = Point.of(from.getColumn() + direction.getTargetCol(), from.getRow() + direction.getTargetRow()); @@ -74,7 +75,7 @@ public int getScore() { } private void validateForward(int signRow) { - if ((team.equals(Team.CHO) && signRow < 0) || (team.equals(Team.HAN) && signRow > 0)) { + if (team.isBackward(signRow)) { throw new IllegalArgumentException("[ERROR] 해당 기물의 이동 규칙에 어긋납니다."); } } diff --git a/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java index 0a279ca815..c4e1ce131d 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.board.Castle; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.CastleDirection; @@ -27,7 +28,7 @@ public AbstractNormalPiece(int score, Team team, PieceType type) { @Override public Points getRoutePoints(Point from, Point to) { - if (!from.inSameCastle(to)) { + if (!Castle.inSameCastle(from, to)) { throw new IllegalArgumentException("[ERROR] 궁성 밖으로 나갈 수 없습니다."); } int pathCol = to.calculatePathColumn(from); diff --git a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java index a359342e24..b4865ea62e 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java @@ -2,6 +2,7 @@ import static java.lang.Math.abs; +import janggi.domain.board.Castle; import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; import janggi.domain.piece.direction.CastleDirection; @@ -73,7 +74,7 @@ public Team getTeam() { } private void validateDirection(Point from, Point to, int signCol, int signRow, int pathCol, int pathRow) { - if (from.inSameCastle(to)) { + if (Castle.inSameCastle(from, to)) { CastleDirection.find(from, signCol, signRow); return; } diff --git a/src/main/java/janggi/domain/point/Point.java b/src/main/java/janggi/domain/point/Point.java index 89dc1a81a9..b5edf5e1b4 100644 --- a/src/main/java/janggi/domain/point/Point.java +++ b/src/main/java/janggi/domain/point/Point.java @@ -9,12 +9,6 @@ public class Point { private static final List> CACHE; private static final int ROW_RANGE = 10; private static final int COLUMN_RANGE = 9; - private static final int HAN_CASTLE_ZONE_ROW_MIN = 7; - private static final int HAN_CASTLE_ZONE_ROW_MAX = 9; - private static final int CHO_CASTLE_ZONE_ROW_MIN =0; - private static final int CHO_CASTLE_ZONE_ROW_MAX =2; - private static final int CASTLE_ZONE_COLUMN_MIN = 3; - private static final int CASTLE_ZONE_COLUMN_MAX = 5; private final int col; private final int row; @@ -49,13 +43,6 @@ public int calculatePathRow(Point from) { return this.row - from.row; } - public boolean inSameCastle(Point other) { - if (this.isCastle() && other.isCastle()) { - return (this.row <= CHO_CASTLE_ZONE_ROW_MAX) == (other.row <= CHO_CASTLE_ZONE_ROW_MAX); - } - return false; - } - public int getColumn() { return col; } @@ -70,10 +57,5 @@ private static void addColumn(List row, int col) { } } - private boolean isCastle() { - boolean isColumnCastle = col >= CASTLE_ZONE_COLUMN_MIN && col <= CASTLE_ZONE_COLUMN_MAX; - boolean isRowHanCastle = row >= HAN_CASTLE_ZONE_ROW_MIN && row <= HAN_CASTLE_ZONE_ROW_MAX; - boolean isRowChoCastle = row <= CHO_CASTLE_ZONE_ROW_MAX && row >= CHO_CASTLE_ZONE_ROW_MIN; - return isColumnCastle && (isRowHanCastle || isRowChoCastle); - } + } From 40e5f49cba6405721090f60e9ea4db77c7d87a89 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:45:44 +0900 Subject: [PATCH 088/110] =?UTF-8?q?test(HanScore):=20=ED=95=9C=EB=82=98?= =?UTF-8?q?=EB=9D=BC=20=EB=B3=B4=EB=84=88=EC=8A=A4=20=EC=A0=90=EC=88=98=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EC=B1=85=EC=9E=84=20=EC=9C=84=EC=9E=84?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/domain/JanggiGameTest.java | 28 +++++++++++++++++++ .../java/janggi/domain/board/BoardTest.java | 10 ------- 2 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 src/test/java/janggi/domain/JanggiGameTest.java diff --git a/src/test/java/janggi/domain/JanggiGameTest.java b/src/test/java/janggi/domain/JanggiGameTest.java new file mode 100644 index 0000000000..9d69c76217 --- /dev/null +++ b/src/test/java/janggi/domain/JanggiGameTest.java @@ -0,0 +1,28 @@ +package janggi.domain; + +import janggi.domain.board.Board; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Pho; +import janggi.domain.piece.Piece; +import janggi.domain.point.Point; +import janggi.domain.status.HanTurn; +import janggi.domain.status.Team; +import java.util.LinkedHashMap; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class JanggiGameTest { + + @Test + @DisplayName("한나라의 기물이 차와 포만 있으면 총합은 1.5점 가산점을 더해서 21.5이다.") + void han_total_score() { + Map pieces = new LinkedHashMap<>(); + pieces.put(Point.of(0, 0), new Cha(Team.HAN)); + pieces.put(Point.of(1, 1), new Pho(Team.HAN)); + Board board = new Board(pieces); + JanggiGame game = new JanggiGame(board, new HanTurn()); + Assertions.assertThat(game.getHanScore()).isEqualTo(21.5); + } +} diff --git a/src/test/java/janggi/domain/board/BoardTest.java b/src/test/java/janggi/domain/board/BoardTest.java index d0eec89904..fbe0ea0139 100644 --- a/src/test/java/janggi/domain/board/BoardTest.java +++ b/src/test/java/janggi/domain/board/BoardTest.java @@ -88,16 +88,6 @@ void can_move_pho_diagonal() { .hasMessageContaining("[ERROR] 이동할 수 없는 방향입니다."); } - @Test - @DisplayName("한나라의 기물이 차와 포만 있으면 총합은 1.5점 가산점을 더해서 21.5이다.") - void han_total_score() { - Map pieces = new LinkedHashMap<>(); - pieces.put(Point.of(0, 0), new Cha(Team.HAN)); - pieces.put(Point.of(1, 1), new Pho(Team.HAN)); - board = new Board(pieces); - Assertions.assertThat(board.calculateScore(Team.HAN)).isEqualTo(21.5); - } - @Test @DisplayName("초나라의 기물이 차와 포만 있으면 총합은 20이다.") void cho_total_score() { From db8cf19befb4da413b60b9ea9746dc81b4c06c3e Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:46:11 +0900 Subject: [PATCH 089/110] =?UTF-8?q?refactor(Team):=20=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=ED=8C=90=EB=8B=A8=20team=EC=97=90=20=EC=9C=84=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/status/Team.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/status/Team.java b/src/main/java/janggi/domain/status/Team.java index 4b36424af2..2a86d0d5fe 100644 --- a/src/main/java/janggi/domain/status/Team.java +++ b/src/main/java/janggi/domain/status/Team.java @@ -1,6 +1,16 @@ package janggi.domain.status; public enum Team { - CHO, - HAN; + CHO { + public boolean isBackward(int signRow) { + return signRow < 0; + } + }, + HAN { + public boolean isBackward(int signRow) { + return signRow > 0; + } + }; + + public abstract boolean isBackward(int signRow); } From d3297ea27c7bfd363064dac814e824096a9973f7 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 15:55:30 +0900 Subject: [PATCH 090/110] =?UTF-8?q?refactor(BoardStatus):=20view=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=A0=81=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=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/JanggiGame.java | 4 ++-- src/main/java/janggi/domain/board/Board.java | 17 ++++------------- .../janggi/presentation/dto/GameStatusInfo.java | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/java/janggi/domain/JanggiGame.java b/src/main/java/janggi/domain/JanggiGame.java index 5042c1b2a0..b3b28344b6 100644 --- a/src/main/java/janggi/domain/JanggiGame.java +++ b/src/main/java/janggi/domain/JanggiGame.java @@ -5,7 +5,7 @@ import janggi.domain.point.Point; import janggi.domain.status.GameStatus; import janggi.domain.status.Team; -import java.util.List; +import java.util.Map; public class JanggiGame { @@ -29,7 +29,7 @@ public Team getWinner() { return gameStatus.getTeam(); } - public List> getBoardStatus() { + public Map getBoardStatus() { return board.getPieces(); } diff --git a/src/main/java/janggi/domain/board/Board.java b/src/main/java/janggi/domain/board/Board.java index 7d8c568d30..abdadb14b7 100644 --- a/src/main/java/janggi/domain/board/Board.java +++ b/src/main/java/janggi/domain/board/Board.java @@ -6,17 +6,13 @@ import janggi.domain.point.Points; import janggi.domain.point.Route; import janggi.domain.status.Team; -import java.util.List; +import java.util.Collections; import java.util.Map; import java.util.Objects; -import java.util.stream.IntStream; public class Board { - private static final int BOARD_HEIGHT = 10; - private static final int BOARD_WIDTH = 9; - - private Map pieces; + private final Map pieces; public Board(Map pieces) { this.pieces = pieces; @@ -44,13 +40,8 @@ public boolean isKingDie() { .count() < 2; } - public List> getPieces() { - return IntStream.range(0, BOARD_HEIGHT) - .mapToObj(row -> IntStream.range(0, BOARD_WIDTH) - .mapToObj(col -> Point.of(col, row)) - .map(point -> this.pieces.get(point)) - .toList() - ).toList(); + public Map getPieces() { + return Collections.unmodifiableMap(this.pieces); } public double calculateScore(Team team) { diff --git a/src/main/java/janggi/presentation/dto/GameStatusInfo.java b/src/main/java/janggi/presentation/dto/GameStatusInfo.java index 0bfeaf7738..074f9217f5 100644 --- a/src/main/java/janggi/presentation/dto/GameStatusInfo.java +++ b/src/main/java/janggi/presentation/dto/GameStatusInfo.java @@ -2,13 +2,17 @@ import janggi.domain.piece.Piece; import janggi.domain.piece.PieceType; +import janggi.domain.point.Point; import janggi.domain.status.Team; import java.util.List; import java.util.Map; +import java.util.stream.IntStream; public record GameStatusInfo( List> pieces ) { + private static final int BOARD_HEIGHT = 10; + private static final int BOARD_WIDTH = 9; private static final Map DISPLAY_NAMES = Map.of( PieceType.CHA, "차", PieceType.PHO, "포", @@ -19,15 +23,24 @@ public record GameStatusInfo( PieceType.JANG, "장" ); - public static GameStatusInfo from(List> board) { + public static GameStatusInfo from(Map board) { return new GameStatusInfo( - board.stream() + getPieces(board).stream() .map(GameStatusInfo::getPieceNames) .toList() .reversed() ); } + private static List> getPieces(Map pieces) { + return IntStream.range(0, BOARD_HEIGHT) + .mapToObj(row -> IntStream.range(0, BOARD_WIDTH) + .mapToObj(col -> Point.of(col, row)) + .map(pieces::get) + .toList() + ).toList(); + } + private static List getPieceNames(List row) { return row.stream() .map(point -> { From 2343f65a759477987c346cbec2cc312ffa0a59b4 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Fri, 3 Apr 2026 16:04:03 +0900 Subject: [PATCH 091/110] =?UTF-8?q?refactor(Repository):=20status=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/infra/JdbcBoardRepository.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 2ec55ae7f4..d52a5435e3 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -36,10 +36,11 @@ public JdbcBoardRepository(DataConnectionManager manager) { public long save(JanggiGame game) { return executeInTransaction(connection -> { long roomId = roomDao.save(GameRoomData.from(game), connection); - List> pieces = game.getBoardStatus(); + Map pieces = game.getBoardStatus(); List data = new ArrayList<>(); - for (int i = 0; i < pieces.size(); i++) { - addPieceData(pieces, i, data); + for (Point point : pieces.keySet()) { + Piece piece = pieces.get(point); + data.add(new PieceData(piece.getType().name(), piece.getTeam().name(), point.getRow(), point.getColumn())); } piecesDao.save(roomId, data, connection); return roomId; @@ -77,16 +78,6 @@ public JanggiGame loadGame(Long gameRoomId) { }); } - private static void addPieceData(List> pieces, int i, List data) { - for (int j = 0; j < pieces.get(i).size(); j++) { - Piece piece = pieces.get(i).get(j); - if (piece == null) { - continue; - } - data.add(new PieceData(piece.getType().name(), piece.getTeam().name(), i, j)); - } - } - private T executeInTransaction(TransactionCallback action) { try (Connection connection = manager.getConnection()) { return processTransaction(connection, action); From 47f689c5a1ce92f8dfc6c7d0207cc16816183fbd Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 09:05:00 +0900 Subject: [PATCH 092/110] =?UTF-8?q?refactor(DAO):=20=EC=97=90=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=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/infra/dao/PiecesDao.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/main/java/janggi/infra/dao/PiecesDao.java b/src/main/java/janggi/infra/dao/PiecesDao.java index 174e0d1741..77210bd7b9 100644 --- a/src/main/java/janggi/infra/dao/PiecesDao.java +++ b/src/main/java/janggi/infra/dao/PiecesDao.java @@ -10,43 +10,55 @@ public class PiecesDao { - public void save(Long roomId, List data, Connection connection) throws SQLException { + public void save(Long roomId, List data, Connection connection) { String sql = "INSERT INTO piece (game_room_id, piece_name, team, row_pos, col_pos) VALUES (?, ?, ?, ?, ?)"; - PreparedStatement pieceStatement = connection.prepareStatement(sql); - for (PieceData piece : data) { - pieceStatement.setLong(1, roomId); - pieceStatement.setString(2, piece.pieceName()); - pieceStatement.setString(3, piece.teamName()); - pieceStatement.setInt(4, piece.row()); - pieceStatement.setInt(5, piece.column()); - pieceStatement.executeUpdate(); + try { + PreparedStatement pieceStatement = connection.prepareStatement(sql); + for (PieceData piece : data) { + pieceStatement.setLong(1, roomId); + pieceStatement.setString(2, piece.pieceName()); + pieceStatement.setString(3, piece.teamName()); + pieceStatement.setInt(4, piece.row()); + pieceStatement.setInt(5, piece.column()); + pieceStatement.executeUpdate(); + } + } catch (SQLException e) { + throw new RuntimeException("[ERROR] 기물을 저장하던 중 오류가 발생했습니다.", e); } } - public void delete(Long roomId, int row, int col, Connection connection) throws SQLException { + public void delete(Long roomId, int row, int col, Connection connection) { String sql = "DELETE FROM piece WHERE game_room_id = ? AND row_pos = ? AND col_pos = ?"; - PreparedStatement killStatement = connection.prepareStatement(sql); - killStatement.setLong(1, roomId); - killStatement.setInt(2, row); - killStatement.setInt(3, col); - killStatement.executeUpdate(); + try { + PreparedStatement killStatement = connection.prepareStatement(sql); + killStatement.setLong(1, roomId); + killStatement.setInt(2, row); + killStatement.setInt(3, col); + killStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] 잡힌 기물을 제거하던 중 오류가 발생했습니다.", e); + } } - public void update(Long roomId, int fromRow, int fromCol, int toRow, int toCol, Connection connection) throws SQLException { + public void update(Long roomId, int fromRow, int fromCol, int toRow, int toCol, Connection connection) { String movePieceSql = "UPDATE piece SET row_pos = ?, col_pos = ? WHERE game_room_id = ? AND row_pos = ? AND col_pos = ?"; - PreparedStatement moveStatement = connection.prepareStatement(movePieceSql); - moveStatement.setInt(1, toRow); - moveStatement.setInt(2, toCol); - moveStatement.setLong(3, roomId); - moveStatement.setInt(4, fromRow); - moveStatement.setInt(5, fromCol); - moveStatement.executeUpdate(); + try { + PreparedStatement moveStatement = connection.prepareStatement(movePieceSql); + moveStatement.setInt(1, toRow); + moveStatement.setInt(2, toCol); + moveStatement.setLong(3, roomId); + moveStatement.setInt(4, fromRow); + moveStatement.setInt(5, fromCol); + moveStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] 기물을 이동하던 종 오류가 발생했습니다.", e); + } } public List findAllByRoomId(Long roomId, Connection connection) { String sql = "SELECT piece_name, team, row_pos, col_pos FROM piece WHERE game_room_id = ?"; - List piecesData = new ArrayList<>(); try { + List piecesData = new ArrayList<>(); PreparedStatement pieceStatement = connection.prepareStatement(sql); pieceStatement.setLong(1, roomId); ResultSet resultSet = pieceStatement.executeQuery(); @@ -60,7 +72,7 @@ public List findAllByRoomId(Long roomId, Connection connection) { } return piecesData; } catch (SQLException e) { - throw new RuntimeException(e); + throw new RuntimeException("[ERROR] 해당 방의 기물을 DB에서 조회하는 중 오류가 발생했습니다.", e); } } } From 8959f184cb145f782752d242456d604474a44eb9 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 09:05:21 +0900 Subject: [PATCH 093/110] =?UTF-8?q?refactor(repository):=20primitive=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/infra/JdbcBoardRepository.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index d52a5435e3..c3a9bb0398 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -48,7 +48,7 @@ public long save(JanggiGame game) { } @Override - public void update(Long roomId, Point from, Point to, JanggiGame game) { + public void update(long roomId, Point from, Point to, JanggiGame game) { executeInTransaction(connection -> { roomDao.update(roomId, GameRoomData.from(game), connection); piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); @@ -58,12 +58,11 @@ public void update(Long roomId, Point from, Point to, JanggiGame game) { } @Override - public JanggiGame loadGame(Long gameRoomId) { - validateIsNull(gameRoomId); + public JanggiGame loadGame(long roomId) { return executeInTransaction(connection -> { - GameRoomData roomData = roomDao.findRoomById(gameRoomId, connection) + GameRoomData roomData = roomDao.findRoomById(roomId, connection) .orElseThrow(() -> new IllegalArgumentException("[ERROR] 존재하지 않는 게임방 입니다.")); - List pieceDatas = piecesDao.findAllByRoomId(gameRoomId, connection); + List pieceDatas = piecesDao.findAllByRoomId(roomId, connection); Map pieces = new LinkedHashMap<>(); pieceDatas.forEach(pieceData -> { PieceType type = PieceType.valueOf(pieceData.pieceName()); @@ -92,6 +91,9 @@ private T processTransaction(Connection connection, TransactionCallback a T result = action.doInTransaction(connection); connection.commit(); return result; + } catch (RuntimeException e) { + connection.rollback(); + throw e; } catch (SQLException e) { connection.rollback(); throw new RuntimeException("[ERROR] 게임 저장 중 트랜잭션 롤백됨", e); @@ -99,10 +101,4 @@ private T processTransaction(Connection connection, TransactionCallback a connection.setAutoCommit(true); } } - - private void validateIsNull(Long roomId) { - if(roomId == null) { - throw new IllegalArgumentException("[ERROR] 잘못된 게임방 ID 입력입니다."); - } - } } From 8a23c971582e7f0743b82b6c3aec8a1da9b59950 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 09:05:25 +0900 Subject: [PATCH 094/110] =?UTF-8?q?refactor(repository):=20primitive=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/BoardRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/janggi/domain/board/BoardRepository.java b/src/main/java/janggi/domain/board/BoardRepository.java index 886c8fb635..6b4e20b0b9 100644 --- a/src/main/java/janggi/domain/board/BoardRepository.java +++ b/src/main/java/janggi/domain/board/BoardRepository.java @@ -5,6 +5,6 @@ public interface BoardRepository { long save(JanggiGame game); - void update(Long roomId, Point from, Point to, JanggiGame game); - JanggiGame loadGame(Long gameRoomId); + void update(long roomId, Point from, Point to, JanggiGame game); + JanggiGame loadGame(long roomId); } From 2341576554afcb05c26c19ff2ed568fde1f8ee73 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 09:11:31 +0900 Subject: [PATCH 095/110] =?UTF-8?q?refactor(DAO):=20try-with-resources=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/infra/dao/PiecesDao.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/janggi/infra/dao/PiecesDao.java b/src/main/java/janggi/infra/dao/PiecesDao.java index 77210bd7b9..ed77fdb2f3 100644 --- a/src/main/java/janggi/infra/dao/PiecesDao.java +++ b/src/main/java/janggi/infra/dao/PiecesDao.java @@ -12,8 +12,7 @@ public class PiecesDao { public void save(Long roomId, List data, Connection connection) { String sql = "INSERT INTO piece (game_room_id, piece_name, team, row_pos, col_pos) VALUES (?, ?, ?, ?, ?)"; - try { - PreparedStatement pieceStatement = connection.prepareStatement(sql); + try (PreparedStatement pieceStatement = connection.prepareStatement(sql)) { for (PieceData piece : data) { pieceStatement.setLong(1, roomId); pieceStatement.setString(2, piece.pieceName()); @@ -29,8 +28,7 @@ public void save(Long roomId, List data, Connection connection) { public void delete(Long roomId, int row, int col, Connection connection) { String sql = "DELETE FROM piece WHERE game_room_id = ? AND row_pos = ? AND col_pos = ?"; - try { - PreparedStatement killStatement = connection.prepareStatement(sql); + try (PreparedStatement killStatement = connection.prepareStatement(sql)) { killStatement.setLong(1, roomId); killStatement.setInt(2, row); killStatement.setInt(3, col); @@ -42,8 +40,7 @@ public void delete(Long roomId, int row, int col, Connection connection) { public void update(Long roomId, int fromRow, int fromCol, int toRow, int toCol, Connection connection) { String movePieceSql = "UPDATE piece SET row_pos = ?, col_pos = ? WHERE game_room_id = ? AND row_pos = ? AND col_pos = ?"; - try { - PreparedStatement moveStatement = connection.prepareStatement(movePieceSql); + try (PreparedStatement moveStatement = connection.prepareStatement(movePieceSql)) { moveStatement.setInt(1, toRow); moveStatement.setInt(2, toCol); moveStatement.setLong(3, roomId); @@ -57,9 +54,8 @@ public void update(Long roomId, int fromRow, int fromCol, int toRow, int toCol, public List findAllByRoomId(Long roomId, Connection connection) { String sql = "SELECT piece_name, team, row_pos, col_pos FROM piece WHERE game_room_id = ?"; - try { + try (PreparedStatement pieceStatement = connection.prepareStatement(sql)) { List piecesData = new ArrayList<>(); - PreparedStatement pieceStatement = connection.prepareStatement(sql); pieceStatement.setLong(1, roomId); ResultSet resultSet = pieceStatement.executeQuery(); while (resultSet.next()) { From 0de26d6924d7e70ea0c8cf205547e8a344d791af Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 09:21:48 +0900 Subject: [PATCH 096/110] =?UTF-8?q?refactor(Repository):=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85=20=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 6 +++++- src/main/java/janggi/infra/JdbcBoardRepository.java | 8 +++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index 70a7d8b06e..bf52ad9ba8 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -4,6 +4,8 @@ import janggi.domain.board.BoardRepository; import janggi.infra.DataConnectionManager; import janggi.infra.JdbcBoardRepository; +import janggi.infra.dao.GameRoomDao; +import janggi.infra.dao.PiecesDao; import janggi.presentation.JanggiGameController; import janggi.presentation.ui.InputView; import janggi.presentation.ui.OutputView; @@ -14,7 +16,9 @@ public class JanggiApplication { public static void main(String[] args) throws SQLException { Server server = Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start(); DataConnectionManager manager = new DataConnectionManager(); - BoardRepository repository = new JdbcBoardRepository(manager); + GameRoomDao roomDao = new GameRoomDao(); + PiecesDao piecesDao = new PiecesDao(); + BoardRepository repository = new JdbcBoardRepository(manager, roomDao, piecesDao); JanggiGameService service = new JanggiGameService(repository); InputView inputView = new InputView(); OutputView outputView = new OutputView(); diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index c3a9bb0398..4f709e9324 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -24,12 +24,14 @@ public class JdbcBoardRepository implements BoardRepository { private final DataConnectionManager manager; - private final GameRoomDao roomDao = new GameRoomDao(); - private final PiecesDao piecesDao = new PiecesDao(); + private final GameRoomDao roomDao; + private final PiecesDao piecesDao; - public JdbcBoardRepository(DataConnectionManager manager) { + public JdbcBoardRepository(DataConnectionManager manager, GameRoomDao roomDao, PiecesDao piecesDao) { this.manager = manager; + this.roomDao = roomDao; + this.piecesDao = piecesDao; } @Override From e8b338bf98b72277e3ce35ab14d55f66ea55f9bb Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:00:47 +0900 Subject: [PATCH 097/110] =?UTF-8?q?refactor(transaction):=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EC=B1=85=EC=9E=84=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=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/JanggiApplication.java | 6 +- .../janggi/application/JanggiGameService.java | 61 ++++++++---- .../janggi/domain/board/BoardRepository.java | 7 +- .../janggi/infra/JdbcBoardRepository.java | 94 ++++++------------- .../janggi/infra/TransactionTemplate.java | 62 ++++++++++++ .../janggi/infra/VoidTransactionCallback.java | 9 ++ 6 files changed, 151 insertions(+), 88 deletions(-) create mode 100644 src/main/java/janggi/infra/TransactionTemplate.java create mode 100644 src/main/java/janggi/infra/VoidTransactionCallback.java diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index bf52ad9ba8..17bdd60696 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -4,6 +4,7 @@ import janggi.domain.board.BoardRepository; import janggi.infra.DataConnectionManager; import janggi.infra.JdbcBoardRepository; +import janggi.infra.TransactionTemplate; import janggi.infra.dao.GameRoomDao; import janggi.infra.dao.PiecesDao; import janggi.presentation.JanggiGameController; @@ -18,8 +19,9 @@ public static void main(String[] args) throws SQLException { DataConnectionManager manager = new DataConnectionManager(); GameRoomDao roomDao = new GameRoomDao(); PiecesDao piecesDao = new PiecesDao(); - BoardRepository repository = new JdbcBoardRepository(manager, roomDao, piecesDao); - JanggiGameService service = new JanggiGameService(repository); + BoardRepository repository = new JdbcBoardRepository(roomDao, piecesDao); + TransactionTemplate template = new TransactionTemplate(manager); + JanggiGameService service = new JanggiGameService(template, repository); InputView inputView = new InputView(); OutputView outputView = new OutputView(); JanggiGameController controller = new JanggiGameController(service, inputView, outputView); diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index 103185ab15..af52337748 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -6,53 +6,80 @@ import janggi.domain.point.Point; import janggi.domain.status.ChoTurn; import janggi.domain.status.Team; +import janggi.infra.TransactionTemplate; import janggi.presentation.dto.GameStatusInfo; public class JanggiGameService { + private final TransactionTemplate template; private final BoardRepository repository; - public JanggiGameService(BoardRepository repository) { + public JanggiGameService(TransactionTemplate template, BoardRepository repository) { + this.template = template; this.repository = repository; } public long startNewGame(Board initBoard) { - JanggiGame game = new JanggiGame(initBoard, new ChoTurn()); - return repository.save(game); + return template.executeInTransaction(connection -> { + JanggiGame game = new JanggiGame(initBoard, new ChoTurn()); + return repository.save(game, connection); + }); } public GameStatusInfo getBoardStatus(Long roomId) { - return GameStatusInfo.from(repository.loadGame(roomId).getBoardStatus()); + return template.executeInTransaction(connection -> { + return GameStatusInfo.from(repository.loadGame(roomId, connection) + .getBoardStatus()); + } + ); } public boolean isFinished(Long roomId) { - return repository.loadGame(roomId) - .isFinished(); + return template.executeInTransaction(connection -> { + return repository.loadGame(roomId, connection) + .isFinished(); + } + ); } public void play(Long roomId, Point from, Point to) { - JanggiGame game = repository.loadGame(roomId); - game.play(from, to); - repository.update(roomId, from, to, game); + template.executeInTransaction(connection -> { + JanggiGame game = repository.loadGame(roomId, connection); + game.play(from, to); + repository.update(roomId, from, to, game, connection); + } + ); } public Team winner(Long roomId) { - return repository.loadGame(roomId) - .getWinner(); + return template.executeInTransaction(connection -> { + return repository.loadGame(roomId, connection) + .getWinner(); + } + ); } public Team currentTurn(Long roomId) { - return repository.loadGame(roomId) - .getTeam(); + return template.executeInTransaction(connection -> { + return repository.loadGame(roomId, connection) + .getTeam(); + } + ); } public double getHanScore(Long roomId) { - return repository.loadGame(roomId) - .getHanScore(); + return template.executeInTransaction(connection -> { + return repository.loadGame(roomId, connection) + .getHanScore(); + } + ); } public double getChoScore(Long roomId) { - return repository.loadGame(roomId) - .getChoScore(); + return template.executeInTransaction(connection -> { + return repository.loadGame(roomId, connection) + .getChoScore(); + } + ); } } diff --git a/src/main/java/janggi/domain/board/BoardRepository.java b/src/main/java/janggi/domain/board/BoardRepository.java index 6b4e20b0b9..504159fc32 100644 --- a/src/main/java/janggi/domain/board/BoardRepository.java +++ b/src/main/java/janggi/domain/board/BoardRepository.java @@ -2,9 +2,10 @@ import janggi.domain.JanggiGame; import janggi.domain.point.Point; +import java.sql.Connection; public interface BoardRepository { - long save(JanggiGame game); - void update(long roomId, Point from, Point to, JanggiGame game); - JanggiGame loadGame(long roomId); + long save(JanggiGame game, Connection connection); + void update(long roomId, Point from, Point to, JanggiGame game, Connection connection); + JanggiGame loadGame(long roomId, Connection connection); } diff --git a/src/main/java/janggi/infra/JdbcBoardRepository.java b/src/main/java/janggi/infra/JdbcBoardRepository.java index 4f709e9324..5c1eb95ef0 100644 --- a/src/main/java/janggi/infra/JdbcBoardRepository.java +++ b/src/main/java/janggi/infra/JdbcBoardRepository.java @@ -14,93 +14,55 @@ import janggi.infra.dto.GameRoomData; import janggi.infra.dto.PieceData; import java.sql.Connection; -import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Optional; public class JdbcBoardRepository implements BoardRepository { - private final DataConnectionManager manager; private final GameRoomDao roomDao; private final PiecesDao piecesDao; - - public JdbcBoardRepository(DataConnectionManager manager, GameRoomDao roomDao, PiecesDao piecesDao) { - this.manager = manager; + public JdbcBoardRepository(GameRoomDao roomDao, PiecesDao piecesDao) { this.roomDao = roomDao; this.piecesDao = piecesDao; } @Override - public long save(JanggiGame game) { - return executeInTransaction(connection -> { - long roomId = roomDao.save(GameRoomData.from(game), connection); - Map pieces = game.getBoardStatus(); - List data = new ArrayList<>(); - for (Point point : pieces.keySet()) { - Piece piece = pieces.get(point); - data.add(new PieceData(piece.getType().name(), piece.getTeam().name(), point.getRow(), point.getColumn())); - } - piecesDao.save(roomId, data, connection); - return roomId; - }); + public long save(JanggiGame game, Connection connection) { + long roomId = roomDao.save(GameRoomData.from(game), connection); + Map pieces = game.getBoardStatus(); + List data = new ArrayList<>(); + for (Point point : pieces.keySet()) { + Piece piece = pieces.get(point); + data.add(new PieceData(piece.getType().name(), piece.getTeam().name(), point.getRow(), point.getColumn())); + } + piecesDao.save(roomId, data, connection); + return roomId; } @Override - public void update(long roomId, Point from, Point to, JanggiGame game) { - executeInTransaction(connection -> { - roomDao.update(roomId, GameRoomData.from(game), connection); - piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); - piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); - return Optional.empty(); - }); + public void update(long roomId, Point from, Point to, JanggiGame game, Connection connection) { + roomDao.update(roomId, GameRoomData.from(game), connection); + piecesDao.delete(roomId, to.getRow(), to.getColumn(), connection); + piecesDao.update(roomId, from.getRow(), from.getColumn(), to.getRow(), to.getColumn(), connection); } @Override - public JanggiGame loadGame(long roomId) { - return executeInTransaction(connection -> { - GameRoomData roomData = roomDao.findRoomById(roomId, connection) - .orElseThrow(() -> new IllegalArgumentException("[ERROR] 존재하지 않는 게임방 입니다.")); - List pieceDatas = piecesDao.findAllByRoomId(roomId, connection); - Map pieces = new LinkedHashMap<>(); - pieceDatas.forEach(pieceData -> { - PieceType type = PieceType.valueOf(pieceData.pieceName()); - Team team = Team.valueOf(pieceData.teamName()); - Point point = Point.of(pieceData.column(), pieceData.row()); - Piece piece = PieceFactory.createPiece(team, type); - pieces.put(point, piece); - }); - Board board = new Board(pieces); - connection.commit(); - return new JanggiGame(board, GameStatusFactory.create(Team.valueOf(roomData.currentTurn()))); + public JanggiGame loadGame(long roomId, Connection connection) { + GameRoomData roomData = roomDao.findRoomById(roomId, connection) + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 존재하지 않는 게임방 입니다.")); + List pieceDatas = piecesDao.findAllByRoomId(roomId, connection); + Map pieces = new LinkedHashMap<>(); + pieceDatas.forEach(pieceData -> { + PieceType type = PieceType.valueOf(pieceData.pieceName()); + Team team = Team.valueOf(pieceData.teamName()); + Point point = Point.of(pieceData.column(), pieceData.row()); + Piece piece = PieceFactory.createPiece(team, type); + pieces.put(point, piece); }); - } - - private T executeInTransaction(TransactionCallback action) { - try (Connection connection = manager.getConnection()) { - return processTransaction(connection, action); - } catch (SQLException e) { - throw new RuntimeException("[ERROR] DB 커넥션 에러", e); - } - } - - private T processTransaction(Connection connection, TransactionCallback action) throws SQLException { - try { - connection.setAutoCommit(false); - T result = action.doInTransaction(connection); - connection.commit(); - return result; - } catch (RuntimeException e) { - connection.rollback(); - throw e; - } catch (SQLException e) { - connection.rollback(); - throw new RuntimeException("[ERROR] 게임 저장 중 트랜잭션 롤백됨", e); - } finally { - connection.setAutoCommit(true); - } + Board board = new Board(pieces); + return new JanggiGame(board, GameStatusFactory.create(Team.valueOf(roomData.currentTurn()))); } } diff --git a/src/main/java/janggi/infra/TransactionTemplate.java b/src/main/java/janggi/infra/TransactionTemplate.java new file mode 100644 index 0000000000..69e9371b40 --- /dev/null +++ b/src/main/java/janggi/infra/TransactionTemplate.java @@ -0,0 +1,62 @@ +package janggi.infra; + +import java.sql.Connection; +import java.sql.SQLException; + +public class TransactionTemplate { + + private final DataConnectionManager manager; + + public TransactionTemplate(DataConnectionManager manager) { + this.manager = manager; + } + + public T executeInTransaction(TransactionCallback action) { + try (Connection connection = manager.getConnection()) { + return processTransaction(connection, action); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] DB 커넥션 에러", e); + } + } + + public void executeInTransaction(VoidTransactionCallback action) { + try (Connection connection = manager.getConnection()) { + processTransaction(connection, action); + } catch (SQLException e) { + throw new RuntimeException("[ERROR] DB 커넥션 에러", e); + } + } + + private T processTransaction(Connection connection, TransactionCallback action) throws SQLException { + try { + connection.setAutoCommit(false); + T result = action.doInTransaction(connection); + connection.commit(); + return result; + } catch (RuntimeException e) { + connection.rollback(); + throw e; + } catch (SQLException e) { + connection.rollback(); + throw new RuntimeException("[ERROR] 게임 저장 중 트랜잭션 롤백됨", e); + } finally { + connection.setAutoCommit(true); + } + } + + private void processTransaction(Connection connection, VoidTransactionCallback action) throws SQLException { + try { + connection.setAutoCommit(false); + action.doInTransaction(connection); + connection.commit(); + } catch (RuntimeException e) { + connection.rollback(); + throw e; + } catch (SQLException e) { + connection.rollback(); + throw new RuntimeException("[ERROR] 게임 저장 중 트랜잭션 롤백됨", e); + } finally { + connection.setAutoCommit(true); + } + } +} diff --git a/src/main/java/janggi/infra/VoidTransactionCallback.java b/src/main/java/janggi/infra/VoidTransactionCallback.java new file mode 100644 index 0000000000..d8bc375670 --- /dev/null +++ b/src/main/java/janggi/infra/VoidTransactionCallback.java @@ -0,0 +1,9 @@ +package janggi.infra; + +import java.sql.Connection; +import java.sql.SQLException; + +@FunctionalInterface +public interface VoidTransactionCallback { + void doInTransaction(Connection connection) throws SQLException; +} From 02e981a074bf99710c9719930ddb91d8f90c34c2 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:01:02 +0900 Subject: [PATCH 098/110] =?UTF-8?q?refactor(team):=20override=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/status/Team.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/janggi/domain/status/Team.java b/src/main/java/janggi/domain/status/Team.java index 2a86d0d5fe..4993c87a75 100644 --- a/src/main/java/janggi/domain/status/Team.java +++ b/src/main/java/janggi/domain/status/Team.java @@ -2,11 +2,13 @@ public enum Team { CHO { + @Override public boolean isBackward(int signRow) { return signRow < 0; } }, HAN { + @Override public boolean isBackward(int signRow) { return signRow > 0; } From 084e61828c4a77ec2f8d5e66fe04984beae1cb66 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:24:25 +0900 Subject: [PATCH 099/110] =?UTF-8?q?refactor(DataConnectionManager):=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=ED=99=94=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 3 +- .../janggi/infra/DataConnectionManager.java | 26 +++------------ .../janggi/infra/H2DataSourceFactory.java | 32 +++++++++++++++++++ 3 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 src/main/java/janggi/infra/H2DataSourceFactory.java diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index 17bdd60696..c4c02dd72d 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -3,6 +3,7 @@ import janggi.application.JanggiGameService; import janggi.domain.board.BoardRepository; import janggi.infra.DataConnectionManager; +import janggi.infra.H2DataSourceFactory; import janggi.infra.JdbcBoardRepository; import janggi.infra.TransactionTemplate; import janggi.infra.dao.GameRoomDao; @@ -16,7 +17,7 @@ public class JanggiApplication { public static void main(String[] args) throws SQLException { Server server = Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start(); - DataConnectionManager manager = new DataConnectionManager(); + DataConnectionManager manager = new DataConnectionManager(H2DataSourceFactory.create()); GameRoomDao roomDao = new GameRoomDao(); PiecesDao piecesDao = new PiecesDao(); BoardRepository repository = new JdbcBoardRepository(roomDao, piecesDao); diff --git a/src/main/java/janggi/infra/DataConnectionManager.java b/src/main/java/janggi/infra/DataConnectionManager.java index 6a048edb70..eefb68e03e 100644 --- a/src/main/java/janggi/infra/DataConnectionManager.java +++ b/src/main/java/janggi/infra/DataConnectionManager.java @@ -1,34 +1,18 @@ package janggi.infra; -import java.io.IOException; -import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; -import java.util.Properties; -import org.h2.jdbcx.JdbcConnectionPool; +import javax.sql.DataSource; public class DataConnectionManager { - private static final int POOL_SIZE = 10; + private final DataSource dataSource; - private final JdbcConnectionPool connectionPool; - - public DataConnectionManager() { - try { - Properties properties = new Properties(); - InputStream inputStream = getClass().getClassLoader().getResourceAsStream("application.properties"); - properties.load(inputStream); - String url = properties.getProperty("db.url"); - String username = properties.getProperty("db.username"); - String password = properties.getProperty("db.password"); - connectionPool = JdbcConnectionPool.create(url, username, password); - connectionPool.setMaxConnections(POOL_SIZE); - } catch (IOException e) { - throw new RuntimeException(e); - } + public DataConnectionManager(DataSource dataSource) { + this.dataSource = dataSource; } public Connection getConnection() throws SQLException { - return connectionPool.getConnection(); + return dataSource.getConnection(); } } diff --git a/src/main/java/janggi/infra/H2DataSourceFactory.java b/src/main/java/janggi/infra/H2DataSourceFactory.java new file mode 100644 index 0000000000..9fb7949e70 --- /dev/null +++ b/src/main/java/janggi/infra/H2DataSourceFactory.java @@ -0,0 +1,32 @@ +package janggi.infra; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import javax.sql.DataSource; +import org.h2.jdbcx.JdbcConnectionPool; + +public class H2DataSourceFactory { + + private static final int POOL_SIZE = 10; + + private H2DataSourceFactory() {} + + public static DataSource create() { + Properties properties = new Properties(); + try (InputStream inputStream = H2DataSourceFactory.class.getClassLoader().getResourceAsStream("application.properties")) { + if (inputStream == null) { + throw new IllegalArgumentException("[ERROR] application.properties 파일을 찾을 수 없습니다."); + } + properties.load(inputStream); + String url = properties.getProperty("db.url"); + String username = properties.getProperty("db.username"); + String password = properties.getProperty("db.password"); + JdbcConnectionPool connectionPool = JdbcConnectionPool.create(url, username, password); + connectionPool.setMaxConnections(POOL_SIZE); + return connectionPool; + } catch (IOException e) { + throw new RuntimeException("[ERROR] DB 설정 파일을 읽는데 실패했습니다.", e); + } + } +} From 2327e39178dc6d1bdd337d3d3a13e55dc126f596 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:33:03 +0900 Subject: [PATCH 100/110] =?UTF-8?q?refactor(SangDirection):=20target=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/direction/MaDirection.java | 2 +- .../domain/piece/direction/SangDirection.java | 30 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/java/janggi/domain/piece/direction/MaDirection.java b/src/main/java/janggi/domain/piece/direction/MaDirection.java index 1eac28e033..2aae96efe7 100644 --- a/src/main/java/janggi/domain/piece/direction/MaDirection.java +++ b/src/main/java/janggi/domain/piece/direction/MaDirection.java @@ -53,7 +53,7 @@ public enum MaDirection { ) ); - List routes; + private final List routes; MaDirection(List routes) { this.routes = routes; diff --git a/src/main/java/janggi/domain/piece/direction/SangDirection.java b/src/main/java/janggi/domain/piece/direction/SangDirection.java index 61b118b794..fee26cdaf9 100644 --- a/src/main/java/janggi/domain/piece/direction/SangDirection.java +++ b/src/main/java/janggi/domain/piece/direction/SangDirection.java @@ -5,81 +5,79 @@ public enum SangDirection { UP_LEFT( + new Offset(-2, -3), List.of( - new Offset(-2, -3), new Offset(0, -1), new Offset(-1, -2) ) ), UP_RIGHT( + new Offset(2, -3), List.of( - new Offset(2, -3), new Offset(0, -1), new Offset(1, -2) ) ), DOWN_LEFT( + new Offset(-2, 3), List.of( - new Offset(-2, 3), new Offset(0, 1), new Offset(-1, 2) ) ), DOWN_RIGHT( + new Offset(2, 3), List.of( - new Offset(2, 3), new Offset(0, 1), new Offset(1, 2) ) ), LEFT_UP( + new Offset(-3, -2), List.of( - new Offset(-3, -2), new Offset(-1, 0), new Offset(-2, -1) ) ), LEFT_DOWN( + new Offset(-3, 2), List.of( - new Offset(-3, 2), new Offset(-1, 0), new Offset(-2, 1) ) ), RIGHT_UP( + new Offset(3, -2), List.of( - new Offset(3, -2), new Offset(1, 0), new Offset(2, -1) ) ), RIGHT_DOWN( + new Offset(3, 2), List.of( - new Offset(3, 2), new Offset(1, 0), new Offset(2, 1) ) ); + private final Offset target; private final List routes; - SangDirection(List routes) { + SangDirection(Offset target, List routes) { + this.target = target; this.routes = routes; } public static SangDirection find(int directionCol, int directionRow) { return Arrays.stream(values()) - .filter(dir -> dir.getTarget().directionColumn() == directionCol - && dir.getTarget().directionRow() == directionRow) + .filter(dir -> dir.target.directionColumn() == directionCol + && dir.target.directionRow() == directionRow) .findFirst() .orElseThrow(() -> new IllegalArgumentException("[ERROR] 상이 이동할 수 없는 방향입니다.")); } public List getWaypoints() { - return routes.subList(1, routes.size()); - } - - private Offset getTarget() { - return routes.getFirst(); + return routes; } } From 8ed75645477da081f620dfc218d64f5c2a07254b Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:34:01 +0900 Subject: [PATCH 101/110] =?UTF-8?q?refactor(Castle):=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/board/Castle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/janggi/domain/board/Castle.java b/src/main/java/janggi/domain/board/Castle.java index 8fd361fde1..74bea00d50 100644 --- a/src/main/java/janggi/domain/board/Castle.java +++ b/src/main/java/janggi/domain/board/Castle.java @@ -11,7 +11,7 @@ public class Castle { private static final int CASTLE_ZONE_COLUMN_MIN = 3; private static final int CASTLE_ZONE_COLUMN_MAX = 5; - public static boolean inSameCastle(Point to, Point from) { + public static boolean inSameCastle(Point from, Point to) { if (isCastle(from.getColumn(), from.getRow()) && isCastle(to.getColumn(), to.getRow())) { return (from.getRow() <= CHO_CASTLE_ZONE_ROW_MAX) == (to.getRow() <= CHO_CASTLE_ZONE_ROW_MAX); } From f776e9a52958f6b9682f78735eba6295b269570a Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:37:15 +0900 Subject: [PATCH 102/110] =?UTF-8?q?refactor(Point):=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/domain/point/Point.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/janggi/domain/point/Point.java b/src/main/java/janggi/domain/point/Point.java index b5edf5e1b4..2f3eb6ea02 100644 --- a/src/main/java/janggi/domain/point/Point.java +++ b/src/main/java/janggi/domain/point/Point.java @@ -10,21 +10,21 @@ public class Point { private static final int ROW_RANGE = 10; private static final int COLUMN_RANGE = 9; - private final int col; + private final int column; private final int row; static { List> temp = new ArrayList<>(); for(int i = 0; i < ROW_RANGE; i++) { List rows = new ArrayList<>(); - addColumn(rows, i); + addColumn(i, rows); temp.add(rows); } CACHE = Collections.unmodifiableList(temp); } - private Point(int col, int row) { - this.col = col; + private Point(int column, int row) { + this.column = column; this.row = row; } @@ -36,7 +36,7 @@ public static Point of(int col, int row) { } public int calculatePathColumn(Point from) { - return this.col - from.col; + return this.column - from.column; } public int calculatePathRow(Point from) { @@ -44,18 +44,16 @@ public int calculatePathRow(Point from) { } public int getColumn() { - return col; + return column; } public int getRow() { return row; } - private static void addColumn(List row, int col) { + private static void addColumn(int column, List row) { for(int i = 0; i < COLUMN_RANGE; i++) { - row.add(new Point(i, col)); + row.add(new Point(i, column)); } } - - } From 3752ea922b90bc53dda63a4d9de361b5c60c92fb Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:48:14 +0900 Subject: [PATCH 103/110] =?UTF-8?q?refactor(PieceType):=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20Piece=EB=B3=84=20S?= =?UTF-8?q?core=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/Implementation/Jang.java | 2 +- .../domain/piece/Implementation/Jol.java | 3 +-- .../domain/piece/Implementation/Ma.java | 4 +--- .../domain/piece/Implementation/Pho.java | 4 +--- .../domain/piece/Implementation/Sa.java | 4 +--- .../domain/piece/Implementation/Sang.java | 4 +--- .../java/janggi/domain/piece/PieceType.java | 24 +++++++++++++------ .../template/AbstractFixedStepPiece.java | 6 ++--- .../piece/template/AbstractNormalPiece.java | 6 ++--- .../piece/template/AbstractStraightPiece.java | 6 ++--- 10 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Implementation/Jang.java b/src/main/java/janggi/domain/piece/Implementation/Jang.java index c7a1bb9e02..377cbb1833 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Jang.java +++ b/src/main/java/janggi/domain/piece/Implementation/Jang.java @@ -6,6 +6,6 @@ public class Jang extends AbstractNormalPiece { public Jang(Team team) { - super(0, team, PieceType.JANG); + super(team, PieceType.JANG); } } diff --git a/src/main/java/janggi/domain/piece/Implementation/Jol.java b/src/main/java/janggi/domain/piece/Implementation/Jol.java index 574128df17..6d4e7f0275 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Jol.java +++ b/src/main/java/janggi/domain/piece/Implementation/Jol.java @@ -15,7 +15,6 @@ public class Jol implements Piece { private static final int MAX_DISTANCE = 1; - private static final int SCORE = 2; private final Team team; private final PieceType type; @@ -71,7 +70,7 @@ public Team getTeam() { @Override public int getScore() { - return SCORE; + return type.getScore(); } private void validateForward(int signRow) { diff --git a/src/main/java/janggi/domain/piece/Implementation/Ma.java b/src/main/java/janggi/domain/piece/Implementation/Ma.java index b1d0284e69..7db1b52d74 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Ma.java +++ b/src/main/java/janggi/domain/piece/Implementation/Ma.java @@ -10,10 +10,8 @@ public class Ma extends AbstractFixedStepPiece { - private static final int SCORE = 5; - public Ma(Team team) { - super(SCORE, team, PieceType.MA); + super(team, PieceType.MA); } @Override diff --git a/src/main/java/janggi/domain/piece/Implementation/Pho.java b/src/main/java/janggi/domain/piece/Implementation/Pho.java index c8c559e19d..1f361bf9d8 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Pho.java +++ b/src/main/java/janggi/domain/piece/Implementation/Pho.java @@ -8,10 +8,8 @@ public class Pho extends AbstractStraightPiece { - private static final int SCORE = 7; - public Pho(Team team) { - super(SCORE, team, PieceType.PHO); + super(team, PieceType.PHO); } @Override diff --git a/src/main/java/janggi/domain/piece/Implementation/Sa.java b/src/main/java/janggi/domain/piece/Implementation/Sa.java index 1175ac9563..f43b955349 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Sa.java +++ b/src/main/java/janggi/domain/piece/Implementation/Sa.java @@ -6,9 +6,7 @@ public class Sa extends AbstractNormalPiece { - private static final int SCORE = 3; - public Sa(Team team) { - super(SCORE, team, PieceType.SA); + super(team, PieceType.SA); } } diff --git a/src/main/java/janggi/domain/piece/Implementation/Sang.java b/src/main/java/janggi/domain/piece/Implementation/Sang.java index 0b3b840d7f..9be6ed7494 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Sang.java +++ b/src/main/java/janggi/domain/piece/Implementation/Sang.java @@ -12,10 +12,8 @@ public class Sang extends AbstractFixedStepPiece { - private static final int SCORE = 3; - public Sang(Team team) { - super(SCORE, team, PieceType.SANG); + super(team, PieceType.SANG); } @Override diff --git a/src/main/java/janggi/domain/piece/PieceType.java b/src/main/java/janggi/domain/piece/PieceType.java index c6b0c4844a..92f8976ed0 100644 --- a/src/main/java/janggi/domain/piece/PieceType.java +++ b/src/main/java/janggi/domain/piece/PieceType.java @@ -1,11 +1,21 @@ package janggi.domain.piece; public enum PieceType { - CHA, - PHO, - MA, - SANG, - JANG, - SA, - JOL; + CHA(13), + PHO(7), + MA(5), + SANG(3), + JANG(0), + SA(3), + JOL(2); + + private final int score; + + PieceType(int score) { + this.score = score; + } + + public int getScore() { + return score; + } } diff --git a/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java b/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java index 77fe346f6e..f8ae68a69a 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractFixedStepPiece.java @@ -11,10 +11,8 @@ public abstract class AbstractFixedStepPiece implements Piece { private final Team team; private final PieceType type; - private final int score; - public AbstractFixedStepPiece(int score, Team team, PieceType type) { - this.score = score; + public AbstractFixedStepPiece(Team team, PieceType type) { this.team = team; this.type = type; } @@ -49,6 +47,6 @@ public Team getTeam() { @Override public int getScore() { - return score; + return type.getScore(); } } diff --git a/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java index c4e1ce131d..458abf079a 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractNormalPiece.java @@ -18,12 +18,10 @@ public abstract class AbstractNormalPiece implements Piece { private final Team team; private final PieceType type; - private final int score; - public AbstractNormalPiece(int score, Team team, PieceType type) { + public AbstractNormalPiece(Team team, PieceType type) { this.team = team; this.type = type; - this.score = score; } @Override @@ -63,7 +61,7 @@ public PieceType getType() { @Override public int getScore() { - return score; + return type.getScore(); } @Override diff --git a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java index b4865ea62e..41f6c9a1b9 100644 --- a/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java +++ b/src/main/java/janggi/domain/piece/template/AbstractStraightPiece.java @@ -17,12 +17,10 @@ public abstract class AbstractStraightPiece implements Piece { private final Team team; private final PieceType type; - private final int score; - public AbstractStraightPiece(int score, Team team, PieceType type) { + public AbstractStraightPiece(Team team, PieceType type) { this.team = team; this.type = type; - this.score = score; } @Override @@ -65,7 +63,7 @@ public PieceType getType() { @Override public int getScore() { - return score; + return type.getScore(); } @Override From 4233e24d585ff0b65a0109dc8fb9dd53556d0e7e Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:48:18 +0900 Subject: [PATCH 104/110] =?UTF-8?q?refactor(PieceType):=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20Piece=EB=B3=84=20S?= =?UTF-8?q?core=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/piece/Implementation/Cha.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/janggi/domain/piece/Implementation/Cha.java b/src/main/java/janggi/domain/piece/Implementation/Cha.java index 154333f6dc..52b5af33a2 100644 --- a/src/main/java/janggi/domain/piece/Implementation/Cha.java +++ b/src/main/java/janggi/domain/piece/Implementation/Cha.java @@ -7,10 +7,8 @@ public class Cha extends AbstractStraightPiece { - private static final int SCORE = 13; - public Cha(Team team) { - super(SCORE, team, PieceType.CHA); + super(team, PieceType.CHA); } public boolean canMove(Route route) { From 36cb534aa5724d7b01d59ecba338e77b36d5150e Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 10:52:18 +0900 Subject: [PATCH 105/110] =?UTF-8?q?refactor(parameter):=20primitive=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/janggi/application/JanggiGameService.java | 14 +++++++------- .../janggi/presentation/JanggiGameController.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index af52337748..9885f00f20 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -26,7 +26,7 @@ public long startNewGame(Board initBoard) { }); } - public GameStatusInfo getBoardStatus(Long roomId) { + public GameStatusInfo getBoardStatus(long roomId) { return template.executeInTransaction(connection -> { return GameStatusInfo.from(repository.loadGame(roomId, connection) .getBoardStatus()); @@ -34,7 +34,7 @@ public GameStatusInfo getBoardStatus(Long roomId) { ); } - public boolean isFinished(Long roomId) { + public boolean isFinished(long roomId) { return template.executeInTransaction(connection -> { return repository.loadGame(roomId, connection) .isFinished(); @@ -42,7 +42,7 @@ public boolean isFinished(Long roomId) { ); } - public void play(Long roomId, Point from, Point to) { + public void play(long roomId, Point from, Point to) { template.executeInTransaction(connection -> { JanggiGame game = repository.loadGame(roomId, connection); game.play(from, to); @@ -51,7 +51,7 @@ public void play(Long roomId, Point from, Point to) { ); } - public Team winner(Long roomId) { + public Team winner(long roomId) { return template.executeInTransaction(connection -> { return repository.loadGame(roomId, connection) .getWinner(); @@ -59,7 +59,7 @@ public Team winner(Long roomId) { ); } - public Team currentTurn(Long roomId) { + public Team currentTurn(long roomId) { return template.executeInTransaction(connection -> { return repository.loadGame(roomId, connection) .getTeam(); @@ -67,7 +67,7 @@ public Team currentTurn(Long roomId) { ); } - public double getHanScore(Long roomId) { + public double getHanScore(long roomId) { return template.executeInTransaction(connection -> { return repository.loadGame(roomId, connection) .getHanScore(); @@ -75,7 +75,7 @@ public double getHanScore(Long roomId) { ); } - public double getChoScore(Long roomId) { + public double getChoScore(long roomId) { return template.executeInTransaction(connection -> { return repository.loadGame(roomId, connection) .getChoScore(); diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index 56b22f9705..0ba28a41e5 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -40,7 +40,7 @@ public void run() { Console.close(); } - private void playGame(Long roomId) { + private void playGame(long roomId) { try { Team team = service.currentTurn(roomId); outputView.printCurrentTurn(team); From df0b17c41032cae24833f59236df6bbe3169f22c Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 11:15:38 +0900 Subject: [PATCH 106/110] =?UTF-8?q?refactor(play):=20play=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/application/JanggiGameService.java | 31 ++++++------------- .../presentation/JanggiGameController.java | 7 ++--- .../presentation/dto/GameStatusInfo.java | 6 +++- .../janggi/presentation/ui/OutputView.java | 5 +-- 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index 9885f00f20..c4175ce01e 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -28,9 +28,13 @@ public long startNewGame(Board initBoard) { public GameStatusInfo getBoardStatus(long roomId) { return template.executeInTransaction(connection -> { - return GameStatusInfo.from(repository.loadGame(roomId, connection) - .getBoardStatus()); - } + JanggiGame game = repository.loadGame(roomId, connection); + return GameStatusInfo.from( + game.getHanScore(), + game.getChoScore(), + game.getBoardStatus() + ); + } ); } @@ -42,11 +46,12 @@ public boolean isFinished(long roomId) { ); } - public void play(long roomId, Point from, Point to) { - template.executeInTransaction(connection -> { + public GameStatusInfo play(long roomId, Point from, Point to) { + return template.executeInTransaction(connection -> { JanggiGame game = repository.loadGame(roomId, connection); game.play(from, to); repository.update(roomId, from, to, game, connection); + return GameStatusInfo.from(game.getHanScore(), game.getChoScore(), game.getBoardStatus()); } ); } @@ -66,20 +71,4 @@ public Team currentTurn(long roomId) { } ); } - - public double getHanScore(long roomId) { - return template.executeInTransaction(connection -> { - return repository.loadGame(roomId, connection) - .getHanScore(); - } - ); - } - - public double getChoScore(long roomId) { - return template.executeInTransaction(connection -> { - return repository.loadGame(roomId, connection) - .getChoScore(); - } - ); - } } diff --git a/src/main/java/janggi/presentation/JanggiGameController.java b/src/main/java/janggi/presentation/JanggiGameController.java index 0ba28a41e5..62b51c2040 100644 --- a/src/main/java/janggi/presentation/JanggiGameController.java +++ b/src/main/java/janggi/presentation/JanggiGameController.java @@ -6,6 +6,7 @@ import janggi.domain.point.Point; import janggi.domain.status.Team; import janggi.presentation.dto.GameCommand; +import janggi.presentation.dto.GameStatusInfo; import janggi.presentation.dto.MoveCommand; import janggi.presentation.dto.PositionInfo; import janggi.presentation.ui.InputView; @@ -32,7 +33,6 @@ public void run() { long roomId = chooseBoard(inputView.chooseNewGame()); outputView.printStartGame(); outputView.printGameStatus(service.getBoardStatus(roomId)); - outputView.printCurrentScore(service.getHanScore(roomId), service.getChoScore(roomId)); while (!service.isFinished(roomId)) { playGame(roomId); } @@ -45,9 +45,8 @@ private void playGame(long roomId) { Team team = service.currentTurn(roomId); outputView.printCurrentTurn(team); MoveCommand points = inputView.readPoints(); - service.play(roomId, points.from(), points.to()); - outputView.printGameStatus(service.getBoardStatus(roomId)); - outputView.printCurrentScore(service.getHanScore(roomId), service.getChoScore(roomId)); + GameStatusInfo play = service.play(roomId, points.from(), points.to()); + outputView.printGameStatus(play); } catch (IllegalArgumentException e) { outputView.printError(e.getMessage()); } diff --git a/src/main/java/janggi/presentation/dto/GameStatusInfo.java b/src/main/java/janggi/presentation/dto/GameStatusInfo.java index 074f9217f5..731c3162cd 100644 --- a/src/main/java/janggi/presentation/dto/GameStatusInfo.java +++ b/src/main/java/janggi/presentation/dto/GameStatusInfo.java @@ -9,6 +9,8 @@ import java.util.stream.IntStream; public record GameStatusInfo( + double hanScore, + double choScore, List> pieces ) { private static final int BOARD_HEIGHT = 10; @@ -23,8 +25,10 @@ public record GameStatusInfo( PieceType.JANG, "장" ); - public static GameStatusInfo from(Map board) { + public static GameStatusInfo from(double hanScore, double choScore, Map board) { return new GameStatusInfo( + hanScore, + choScore, getPieces(board).stream() .map(GameStatusInfo::getPieceNames) .toList() diff --git a/src/main/java/janggi/presentation/ui/OutputView.java b/src/main/java/janggi/presentation/ui/OutputView.java index 877db204b1..9c7f64b0cd 100644 --- a/src/main/java/janggi/presentation/ui/OutputView.java +++ b/src/main/java/janggi/presentation/ui/OutputView.java @@ -22,10 +22,7 @@ public void printWinner(Team winner) { public void printGameStatus(GameStatusInfo status) { status.pieces() .forEach(System.out::println); - } - - public void printCurrentScore(double hanScore, double choScore) { - System.out.printf("한 : %.1f, 초 : %.1f\n", hanScore, choScore); + System.out.printf("한 : %.1f, 초 : %.1f\n", status.hanScore(), status.choScore()); } public void printStartGame() { From 3de88e369fbd91c171dd971d047d5c7d9949a945 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 11:18:06 +0900 Subject: [PATCH 107/110] =?UTF-8?q?refactor(Transaction):=20void=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=20=EB=AF=B8=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/infra/VoidTransactionCallback.java | 9 ------- .../TransactionTemplate.java | 27 ++----------------- 2 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 src/main/java/janggi/infra/VoidTransactionCallback.java rename src/main/java/janggi/infra/{ => transaction}/TransactionTemplate.java (56%) diff --git a/src/main/java/janggi/infra/VoidTransactionCallback.java b/src/main/java/janggi/infra/VoidTransactionCallback.java deleted file mode 100644 index d8bc375670..0000000000 --- a/src/main/java/janggi/infra/VoidTransactionCallback.java +++ /dev/null @@ -1,9 +0,0 @@ -package janggi.infra; - -import java.sql.Connection; -import java.sql.SQLException; - -@FunctionalInterface -public interface VoidTransactionCallback { - void doInTransaction(Connection connection) throws SQLException; -} diff --git a/src/main/java/janggi/infra/TransactionTemplate.java b/src/main/java/janggi/infra/transaction/TransactionTemplate.java similarity index 56% rename from src/main/java/janggi/infra/TransactionTemplate.java rename to src/main/java/janggi/infra/transaction/TransactionTemplate.java index 69e9371b40..aa95236bcb 100644 --- a/src/main/java/janggi/infra/TransactionTemplate.java +++ b/src/main/java/janggi/infra/transaction/TransactionTemplate.java @@ -1,5 +1,6 @@ -package janggi.infra; +package janggi.infra.transaction; +import janggi.infra.datasource.DataConnectionManager; import java.sql.Connection; import java.sql.SQLException; @@ -19,14 +20,6 @@ public T executeInTransaction(TransactionCallback action) { } } - public void executeInTransaction(VoidTransactionCallback action) { - try (Connection connection = manager.getConnection()) { - processTransaction(connection, action); - } catch (SQLException e) { - throw new RuntimeException("[ERROR] DB 커넥션 에러", e); - } - } - private T processTransaction(Connection connection, TransactionCallback action) throws SQLException { try { connection.setAutoCommit(false); @@ -43,20 +36,4 @@ private T processTransaction(Connection connection, TransactionCallback a connection.setAutoCommit(true); } } - - private void processTransaction(Connection connection, VoidTransactionCallback action) throws SQLException { - try { - connection.setAutoCommit(false); - action.doInTransaction(connection); - connection.commit(); - } catch (RuntimeException e) { - connection.rollback(); - throw e; - } catch (SQLException e) { - connection.rollback(); - throw new RuntimeException("[ERROR] 게임 저장 중 트랜잭션 롤백됨", e); - } finally { - connection.setAutoCommit(true); - } - } } From d26b08a4ddc0ca65743ee57d2d52cc5e9a0da462 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 11:18:32 +0900 Subject: [PATCH 108/110] =?UTF-8?q?chore(infra):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/janggi/JanggiApplication.java | 6 +++--- src/main/java/janggi/application/JanggiGameService.java | 2 +- .../infra/{ => datasource}/DataConnectionManager.java | 2 +- .../janggi/infra/{ => datasource}/H2DataSourceFactory.java | 2 +- .../janggi/infra/{ => transaction}/TransactionCallback.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/janggi/infra/{ => datasource}/DataConnectionManager.java (92%) rename src/main/java/janggi/infra/{ => datasource}/H2DataSourceFactory.java (97%) rename src/main/java/janggi/infra/{ => transaction}/TransactionCallback.java (84%) diff --git a/src/main/java/janggi/JanggiApplication.java b/src/main/java/janggi/JanggiApplication.java index c4c02dd72d..7783188451 100644 --- a/src/main/java/janggi/JanggiApplication.java +++ b/src/main/java/janggi/JanggiApplication.java @@ -2,10 +2,10 @@ import janggi.application.JanggiGameService; import janggi.domain.board.BoardRepository; -import janggi.infra.DataConnectionManager; -import janggi.infra.H2DataSourceFactory; +import janggi.infra.datasource.DataConnectionManager; +import janggi.infra.datasource.H2DataSourceFactory; import janggi.infra.JdbcBoardRepository; -import janggi.infra.TransactionTemplate; +import janggi.infra.transaction.TransactionTemplate; import janggi.infra.dao.GameRoomDao; import janggi.infra.dao.PiecesDao; import janggi.presentation.JanggiGameController; diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index c4175ce01e..53aa6275dd 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -6,7 +6,7 @@ import janggi.domain.point.Point; import janggi.domain.status.ChoTurn; import janggi.domain.status.Team; -import janggi.infra.TransactionTemplate; +import janggi.infra.transaction.TransactionTemplate; import janggi.presentation.dto.GameStatusInfo; public class JanggiGameService { diff --git a/src/main/java/janggi/infra/DataConnectionManager.java b/src/main/java/janggi/infra/datasource/DataConnectionManager.java similarity index 92% rename from src/main/java/janggi/infra/DataConnectionManager.java rename to src/main/java/janggi/infra/datasource/DataConnectionManager.java index eefb68e03e..80cb2f3f09 100644 --- a/src/main/java/janggi/infra/DataConnectionManager.java +++ b/src/main/java/janggi/infra/datasource/DataConnectionManager.java @@ -1,4 +1,4 @@ -package janggi.infra; +package janggi.infra.datasource; import java.sql.Connection; import java.sql.SQLException; diff --git a/src/main/java/janggi/infra/H2DataSourceFactory.java b/src/main/java/janggi/infra/datasource/H2DataSourceFactory.java similarity index 97% rename from src/main/java/janggi/infra/H2DataSourceFactory.java rename to src/main/java/janggi/infra/datasource/H2DataSourceFactory.java index 9fb7949e70..d9f4baf493 100644 --- a/src/main/java/janggi/infra/H2DataSourceFactory.java +++ b/src/main/java/janggi/infra/datasource/H2DataSourceFactory.java @@ -1,4 +1,4 @@ -package janggi.infra; +package janggi.infra.datasource; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/janggi/infra/TransactionCallback.java b/src/main/java/janggi/infra/transaction/TransactionCallback.java similarity index 84% rename from src/main/java/janggi/infra/TransactionCallback.java rename to src/main/java/janggi/infra/transaction/TransactionCallback.java index a91e87b029..4e5d1a617d 100644 --- a/src/main/java/janggi/infra/TransactionCallback.java +++ b/src/main/java/janggi/infra/transaction/TransactionCallback.java @@ -1,4 +1,4 @@ -package janggi.infra; +package janggi.infra.transaction; import java.sql.Connection; import java.sql.SQLException; From 42cf9c5a3f756fad5e2c0637c6476e05d08510e6 Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 11:50:33 +0900 Subject: [PATCH 109/110] =?UTF-8?q?test(Repository):=20Repository=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5,=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/infra/JdbcBoardRepositoryTest.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/test/java/janggi/infra/JdbcBoardRepositoryTest.java diff --git a/src/test/java/janggi/infra/JdbcBoardRepositoryTest.java b/src/test/java/janggi/infra/JdbcBoardRepositoryTest.java new file mode 100644 index 0000000000..75986cebd1 --- /dev/null +++ b/src/test/java/janggi/infra/JdbcBoardRepositoryTest.java @@ -0,0 +1,87 @@ +package janggi.infra; + +import janggi.domain.JanggiGame; +import janggi.domain.board.Board; +import janggi.domain.piece.Implementation.Cha; +import janggi.domain.piece.Implementation.Ma; +import janggi.domain.piece.Piece; +import janggi.domain.piece.PieceType; +import janggi.domain.point.Point; +import janggi.domain.status.ChoTurn; +import janggi.domain.status.Team; +import janggi.infra.dao.GameRoomDao; +import janggi.infra.dao.PiecesDao; +import janggi.infra.datasource.H2DataSourceFactory; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.sql.DataSource; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class JdbcBoardRepositoryTest { + + private JdbcBoardRepository repository; + private Connection connection; + + @BeforeEach + void setUp() throws SQLException { + DataSource dataSource = H2DataSourceFactory.create(); + repository = new JdbcBoardRepository(new GameRoomDao(), new PiecesDao()); + connection = dataSource.getConnection(); + connection.setAutoCommit(false); + } + + @AfterEach + void reset() throws SQLException { + connection.rollback(); + connection.close(); + } + + @Test + @DisplayName("새로운 게임을 저장하고, 불러오면 두 게임 상태가 일치 해야한다.") + void same_status() { + Map pieces = new LinkedHashMap<>(); + pieces.put(Point.of(0, 0), new Cha(Team.CHO)); + pieces.put(Point.of(0, 1), new Ma(Team.CHO)); + Board board = new Board(pieces); + JanggiGame game = new JanggiGame(board, new ChoTurn()); + long roomId = repository.save(game, connection); + JanggiGame loadedGame = repository.loadGame(roomId, connection); + Assertions.assertThat(game.getTeam()).isEqualTo(loadedGame.getTeam()); + Assertions.assertThat(game.getChoScore()).isEqualTo(loadedGame.getChoScore()); + Assertions.assertThat(game.getHanScore()).isEqualTo(loadedGame.getHanScore()); + } + + @Test + @DisplayName("기물을 이동하고, 불러오면 이동된 기물의 위치가 반영되어 있어야한다.") + void play_point() { + Map pieces = new LinkedHashMap<>(); + pieces.put(Point.of(0, 0), new Cha(Team.CHO)); + pieces.put(Point.of(1, 1), new Ma(Team.CHO)); + Board board = new Board(pieces); + JanggiGame game = new JanggiGame(board, new ChoTurn()); + long roomId = repository.save(game, connection); + + Point from = Point.of(0,0); + Point to = Point.of(0,2); + game.play(from, to); + repository.update(roomId, from, to, game, connection); + + JanggiGame loadedGame = repository.loadGame(roomId, connection); + Assertions.assertThat(loadedGame.getBoardStatus().get(from)).isNull(); + Assertions.assertThat(loadedGame.getBoardStatus().get(to)).isNotNull(); + Assertions.assertThat(loadedGame.getBoardStatus().get(to).getType()).isEqualTo(PieceType.CHA); + } + + @Test + @DisplayName("존재하지 않는 방번호로 조회하면 예외가 발생한다.") + void not_found_room() { + Assertions.assertThatThrownBy(() -> repository.loadGame(-1, connection)) + .isInstanceOf(IllegalArgumentException.class); + } +} From c52dbc7bd8b200243bfab9e4fe9dd6fef405494e Mon Sep 17 00:00:00 2001 From: juntae6942 Date: Sat, 4 Apr 2026 11:55:32 +0900 Subject: [PATCH 110/110] =?UTF-8?q?refactor(Service):=20=ED=8F=AC=EB=A7=B7?= =?UTF-8?q?=ED=8C=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../janggi/application/JanggiGameService.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/janggi/application/JanggiGameService.java b/src/main/java/janggi/application/JanggiGameService.java index 53aa6275dd..bebb82188b 100644 --- a/src/main/java/janggi/application/JanggiGameService.java +++ b/src/main/java/janggi/application/JanggiGameService.java @@ -39,10 +39,9 @@ public GameStatusInfo getBoardStatus(long roomId) { } public boolean isFinished(long roomId) { - return template.executeInTransaction(connection -> { - return repository.loadGame(roomId, connection) - .isFinished(); - } + return template.executeInTransaction(connection -> + repository.loadGame(roomId, connection) + .isFinished() ); } @@ -57,18 +56,16 @@ public GameStatusInfo play(long roomId, Point from, Point to) { } public Team winner(long roomId) { - return template.executeInTransaction(connection -> { - return repository.loadGame(roomId, connection) - .getWinner(); - } + return template.executeInTransaction(connection -> + repository.loadGame(roomId, connection) + .getWinner() ); } public Team currentTurn(long roomId) { - return template.executeInTransaction(connection -> { - return repository.loadGame(roomId, connection) - .getTeam(); - } + return template.executeInTransaction(connection -> + repository.loadGame(roomId, connection) + .getTeam() ); } }