From e14d0469ec93f2b3c0aaa8547b1761536afa38ba Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 17:22:53 +0900 Subject: [PATCH 01/45] =?UTF-8?q?docs:=203=EB=8B=A8=EA=B3=84=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 894296bb25e..ade9a20c4de 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,21 @@ - 단, 폰은 이동할 수 있는 위치에 상대 진영의 말이 있는 경우, 그 위치로 이동할 수 없다. 6. 체스 말이 이동할 수 있는 위치에 같은 진영의 말이 있는 경우, 그 위치로 이동할 수 없다. +### 게임 종료 조건 + +1. 킹이 잡히는 팀이 게임에서 진다. 킹이 잡히 게임이 종료된다. + +### 점수 + +1. 각 팀에는 점수가 있다. 팀의 점수는 살아있는 체스 말의 점수의 합이다. +2. 각 말의 점수는 다음과 같다. + - 퀸 : 9점 + - 룩 : 5점 + - 비숍 : 3점 + - 나이트 : 2.5점 + - 폰 : 1점 + - 같은 세로 위치에 같은 색의 폰이 여러개 있는 경우, 그 폰들은 점수가 0.5점이다. + ## 기능 목록 - [x] 체스 말 @@ -48,10 +63,15 @@ - [x] 체스 보드 - [x] 올바른 턴인지 확인한다 - [x] 잡힌 말을 제거한다 +- [ ] 점수 + - [ ] 각 말의 점수 계산 기능 + - [ ] 폰의 점수 보정 기능 + - [ ] 각 팀의 점수 계산 기능 - [x] 사용자 입력 기능 - [x] 이동 위치 명령어 입력 기능 - [x] 게임 시작 명령어 입력 기능 - [x] 게임 종료 명령어 입력 기능 + - [ ] 점수 조회 명령어 입력 기능 - [x] 출력 기능 - [x] 체스 판 출력 기능 - [x] 안내 문구 출력 기능 From c4e7d044aae4420142603e030dae9d9cc7447610 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 17:47:29 +0900 Subject: [PATCH 02/45] =?UTF-8?q?feat:=20=EA=B0=81=20=EB=A7=90=EC=9D=98=20?= =?UTF-8?q?=EC=A0=90=EC=88=98=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=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 --- README.md | 2 +- src/main/java/chess/domain/piece/Bishop.java | 5 +++++ src/main/java/chess/domain/piece/King.java | 5 +++++ src/main/java/chess/domain/piece/Knight.java | 5 +++++ src/main/java/chess/domain/piece/Pawn.java | 5 +++++ src/main/java/chess/domain/piece/Piece.java | 2 ++ src/main/java/chess/domain/piece/Queen.java | 5 +++++ src/main/java/chess/domain/piece/Rook.java | 5 +++++ 8 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ade9a20c4de..82ac754450e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ - [x] 올바른 턴인지 확인한다 - [x] 잡힌 말을 제거한다 - [ ] 점수 - - [ ] 각 말의 점수 계산 기능 + - [x] 각 말의 점수 계산 기능 - [ ] 폰의 점수 보정 기능 - [ ] 각 팀의 점수 계산 기능 - [x] 사용자 입력 기능 diff --git a/src/main/java/chess/domain/piece/Bishop.java b/src/main/java/chess/domain/piece/Bishop.java index 4fed465d93b..16ba67ebe26 100644 --- a/src/main/java/chess/domain/piece/Bishop.java +++ b/src/main/java/chess/domain/piece/Bishop.java @@ -24,4 +24,9 @@ public Optional tryMoveAssumeAlone(Position targetPosition, Che public PieceType getPieceType() { return PieceType.BISHOP; } + + @Override + public double getPoint() { + return 3.0; + } } diff --git a/src/main/java/chess/domain/piece/King.java b/src/main/java/chess/domain/piece/King.java index cc55f36e05a..dba4ecff778 100644 --- a/src/main/java/chess/domain/piece/King.java +++ b/src/main/java/chess/domain/piece/King.java @@ -24,4 +24,9 @@ public Optional tryMoveAssumeAloneAndCheckRoute(Position target public PieceType getPieceType() { return PieceType.KING; } + + @Override + public double getPoint() { + return 0.0; + } } diff --git a/src/main/java/chess/domain/piece/Knight.java b/src/main/java/chess/domain/piece/Knight.java index 207c260cf14..8816c91c966 100644 --- a/src/main/java/chess/domain/piece/Knight.java +++ b/src/main/java/chess/domain/piece/Knight.java @@ -29,4 +29,9 @@ private boolean isMovablePosition(Position targetPosition) { public PieceType getPieceType() { return PieceType.KNIGHT; } + + @Override + public double getPoint() { + return 2.5; + } } diff --git a/src/main/java/chess/domain/piece/Pawn.java b/src/main/java/chess/domain/piece/Pawn.java index ccb63d82448..120db8a6040 100644 --- a/src/main/java/chess/domain/piece/Pawn.java +++ b/src/main/java/chess/domain/piece/Pawn.java @@ -84,4 +84,9 @@ private boolean isOtherTeam(Position targetPosition, ChessBoard chessBoard) { public PieceType getPieceType() { return PieceType.PAWN; } + + @Override + public double getPoint() { + return 1.0; + } } diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index a83e97dbb20..56033bdb03b 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -15,4 +15,6 @@ public interface Piece { int getColumn(); int getRow(); + + double getPoint(); } diff --git a/src/main/java/chess/domain/piece/Queen.java b/src/main/java/chess/domain/piece/Queen.java index 33f72372707..100aaf3c219 100644 --- a/src/main/java/chess/domain/piece/Queen.java +++ b/src/main/java/chess/domain/piece/Queen.java @@ -28,4 +28,9 @@ public Optional tryMoveAssumeAlone(Position targetPosition, Che public PieceType getPieceType() { return QUEEN; } + + @Override + public double getPoint() { + return 9.0; + } } diff --git a/src/main/java/chess/domain/piece/Rook.java b/src/main/java/chess/domain/piece/Rook.java index 976842a9349..2b09226f107 100644 --- a/src/main/java/chess/domain/piece/Rook.java +++ b/src/main/java/chess/domain/piece/Rook.java @@ -22,4 +22,9 @@ public Optional tryMoveAssumeAlone(Position targetPosition, Che public PieceType getPieceType() { return PieceType.ROOK; } + + @Override + public double getPoint() { + return 5.0; + } } From a66294807c8665aaf833ad714bfa2ef33c5c48a6 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 22:19:40 +0900 Subject: [PATCH 03/45] =?UTF-8?q?feat:=20=EA=B0=81=20=ED=8C=80=EC=9D=98=20?= =?UTF-8?q?=EC=A0=90=EC=88=98=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=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 --- README.md | 6 +-- .../java/chess/domain/board/ChessBoard.java | 39 ++++++++++++++++++- .../chess/domain/piece/AbstractPiece.java | 5 +++ src/main/java/chess/domain/piece/Piece.java | 2 + .../chess/domain/board/ChessBoardTest.java | 31 +++++++++++++++ 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 82ac754450e..bada527f0d8 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,10 @@ - [x] 체스 보드 - [x] 올바른 턴인지 확인한다 - [x] 잡힌 말을 제거한다 -- [ ] 점수 +- [x] 점수 - [x] 각 말의 점수 계산 기능 - - [ ] 폰의 점수 보정 기능 - - [ ] 각 팀의 점수 계산 기능 + - [x] 폰의 점수 보정 기능 + - [x] 각 팀의 점수 계산 기능 - [x] 사용자 입력 기능 - [x] 이동 위치 명령어 입력 기능 - [x] 게임 시작 명령어 입력 기능 diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index 418ce4de306..e5ba25f617c 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -5,11 +5,14 @@ import chess.domain.Position; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; +import chess.domain.piece.PieceType; import chess.domain.piece.Team; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; public class ChessBoard { private final List piecesOnBoard; @@ -40,7 +43,7 @@ boolean move(Position from, Position to) { private boolean isEmptyPosition(Position from) { Optional optionalPiece = piecesOnBoard.stream() - .filter(piece1 -> piece1.isOn(from)) + .filter(piece -> piece.isOn(from)) .findFirst(); return optionalPiece.isEmpty(); } @@ -91,4 +94,38 @@ public Optional whichTeam(Position position) { List getPiecesOnBoard() { return Collections.unmodifiableList(piecesOnBoard); } + + double calculatePoint(Team team) { + double totalPoint = calculateWithOutSameColumnPawn(team); + Map> pawnsAtSameColumn = pawnGroupingByColumn(team); + double correctionPoint = calculatePawnCorrectionPoint(pawnsAtSameColumn); + return totalPoint - correctionPoint; + } + + private double calculateWithOutSameColumnPawn(Team team) { + return piecesOnBoard.stream() + .filter(piece -> piece.isTeamWith(team)) + .mapToDouble(Piece::getPoint) + .reduce(0.0, Double::sum); + } + + private Map> pawnGroupingByColumn(Team team) { + return piecesOnBoard.stream() + .filter(piece -> piece.isTeamWith(team)) + .filter(this::isPawn) + .collect(Collectors.groupingBy(Piece::getColumn, Collectors.toUnmodifiableList())); + } + + private boolean isPawn(Piece piece) { + PieceType pieceType = piece.getPieceType(); + return pieceType.equals(PieceType.PAWN); + } + + private double calculatePawnCorrectionPoint(Map> pawnsAtSameColumn) { + final double correctionPointPerPawn = 0.5; + return pawnsAtSameColumn.values().stream() + .filter(pieces -> pieces.size() > 1) + .mapToDouble(pieces -> pieces.size() * correctionPointPerPawn) + .reduce(0.0, Double::sum); + } } diff --git a/src/main/java/chess/domain/piece/AbstractPiece.java b/src/main/java/chess/domain/piece/AbstractPiece.java index 10aa97fc999..c3efb7511c6 100644 --- a/src/main/java/chess/domain/piece/AbstractPiece.java +++ b/src/main/java/chess/domain/piece/AbstractPiece.java @@ -46,6 +46,11 @@ public int getRow() { return position.getRow(); } + @Override + public boolean isTeamWith(Team team) { + return this.team.equals(team); + } + protected Position getPosition() { return position; } diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index 56033bdb03b..4182e5d4bc3 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -17,4 +17,6 @@ public interface Piece { int getRow(); double getPoint(); + + boolean isTeamWith(Team team); } diff --git a/src/test/java/chess/domain/board/ChessBoardTest.java b/src/test/java/chess/domain/board/ChessBoardTest.java index 43776ae928d..1371764df9f 100644 --- a/src/test/java/chess/domain/board/ChessBoardTest.java +++ b/src/test/java/chess/domain/board/ChessBoardTest.java @@ -1,8 +1,10 @@ package chess.domain.board; import static chess.domain.Position.A1; +import static chess.domain.Position.A2; import static chess.domain.Position.A3; import static chess.domain.Position.A4; +import static chess.domain.Position.A5; import static chess.domain.Position.A6; import static chess.domain.Position.B1; import static chess.domain.Position.B2; @@ -24,6 +26,7 @@ import static chess.domain.Position.H1; import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; +import static org.junit.jupiter.api.Assertions.assertAll; import chess.domain.Position; import chess.domain.piece.Bishop; @@ -38,6 +41,7 @@ import java.util.Optional; import java.util.stream.Stream; import org.assertj.core.api.Assertions; +import org.assertj.core.data.Offset; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -154,4 +158,31 @@ void whichTeamWhenEmpty() { Assertions.assertThat(actual) .isEmpty(); } + + @Test + @DisplayName("각 팀의 점수가 잘 계산되는지 검증") + void calculatePoint() { + ChessBoard chessBoard = new ChessBoard(); + double whiteTeamPoint = chessBoard.calculatePoint(WHITE); + double blackTeamPoint = chessBoard.calculatePoint(BLACK); + Offset offset = Offset.offset(0.01); + assertAll( + () -> Assertions.assertThat(whiteTeamPoint).isCloseTo(38.0, offset), + () -> Assertions.assertThat(blackTeamPoint).isCloseTo(38.0, offset) + ); + } + + @Test + @DisplayName("같은 열의 폰이 포함된 각 팀의 점수가 잘 계산되는지 검증") + void calculatePointWithPawn() { + ChessBoard chessBoard = new ChessBoard(new Pawn(A2, BLACK), new Pawn(B2, BLACK), new Pawn(A3, BLACK), + new Pawn(A4, WHITE), new Pawn(A5, WHITE), new Pawn(A6, WHITE)); + double whiteTeamPoint = chessBoard.calculatePoint(WHITE); + double blackTeamPoint = chessBoard.calculatePoint(BLACK); + Offset offset = Offset.offset(0.01); + assertAll( + () -> Assertions.assertThat(blackTeamPoint).isCloseTo(2.0, offset), + () -> Assertions.assertThat(whiteTeamPoint).isCloseTo(1.5, offset) + ); + } } From af2b4811c208d171af69e03f6f8f9d0fb12081c0 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 22:24:12 +0900 Subject: [PATCH 04/45] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?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 --- .../domain/piece/AbstractCatchOnMovePiece.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java b/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java index c0ef9c8b4e0..2d2c6e1d6a4 100644 --- a/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java +++ b/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java @@ -33,16 +33,22 @@ protected abstract Optional tryMoveAssumeAloneAndCheckRoute(Pos private boolean isMyTeam(Position targetPosition, ChessBoard chessBoard) { return chessBoard.whichTeam(targetPosition) - .filter(team -> team.equals(getTeam())) + .filter(this::isMyTeam) .isPresent(); } + private boolean isMyTeam(Team team) { + return team.equals(getTeam()); + } + private boolean isOtherTeam(Position targetPosition, ChessBoard chessBoard) { return chessBoard.whichTeam(targetPosition) - .filter(team -> { - Team otherTeam = getTeam().otherTeam(); - return team.equals(otherTeam); - }) + .filter(this::isOtherTeam) .isPresent(); } + + private boolean isOtherTeam(Team team) { + Team otherTeam = getTeam().otherTeam(); + return team.equals(otherTeam); + } } From 0178b177f04bdab35bfd1851be48a17b71ffaf06 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 22:38:15 +0900 Subject: [PATCH 05/45] =?UTF-8?q?feat:=20=EC=A0=90=EC=88=98=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=AA=85=EB=A0=B9=EC=96=B4=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=EC=A0=90=EC=88=98=20=EC=B6=9C?= =?UTF-8?q?=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 --- README.md | 3 ++- src/main/java/chess/Application.java | 24 +++++++++++++++---- .../chess/domain/board/ChessBoardWrapper.java | 5 ++++ .../java/chess/domain/game/ChessGame.java | 5 ++++ .../java/chess/domain/game/StatusCommand.java | 20 ++++++++++++++++ src/main/java/chess/view/InputView.java | 23 ++++++++++++++++++ src/main/java/chess/view/OutputView.java | 4 ++++ 7 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/main/java/chess/domain/game/StatusCommand.java diff --git a/README.md b/README.md index bada527f0d8..9806d56f595 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,8 @@ - [x] 이동 위치 명령어 입력 기능 - [x] 게임 시작 명령어 입력 기능 - [x] 게임 종료 명령어 입력 기능 - - [ ] 점수 조회 명령어 입력 기능 + - [x] 점수 조회 명령어 입력 기능 - [x] 출력 기능 - [x] 체스 판 출력 기능 - [x] 안내 문구 출력 기능 + - [x] 점수 출력 기능 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index f23dbba3c1f..c220162e5ec 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -5,6 +5,7 @@ import chess.domain.Position; import chess.domain.game.ChessGame; import chess.domain.game.Command; +import chess.domain.game.StatusCommand; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import chess.domain.piece.Team; @@ -25,10 +26,10 @@ public static void main(String[] args) { List pieceDTOS = piecesToDTO(piecesOnBoard); OutputView.printChessBoard(pieceDTOS); - Command endOrMove = InputView.readEndOrMove(); - while (!isEndCommand(endOrMove)) { - playGame(endOrMove, chessGame); - endOrMove = InputView.readEndOrMove(); + Command endOrMoveOrStatus = InputView.readEndOrMoveOrStatus(); + while (!isEndCommand(endOrMoveOrStatus)) { + playGameOrPrintStatus(endOrMoveOrStatus, chessGame); + endOrMoveOrStatus = InputView.readEndOrMoveOrStatus(); } } @@ -46,6 +47,21 @@ private static boolean isEndCommand(Command command) { return command.equals(END_COMMAND); } + private static void playGameOrPrintStatus(Command moveOrStatus, ChessGame chessGame) { + if (moveOrStatus.equals(StatusCommand.STATUS_COMMAND)) { + printStatus(chessGame); + return; + } + playGame(moveOrStatus, chessGame); + } + + private static void printStatus(ChessGame chessGame) { + double whiteTeamPoint = chessGame.calculatePoint(Team.WHITE); + OutputView.printStatus(Team.WHITE, whiteTeamPoint); + double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); + OutputView.printStatus(Team.BLACK, blackTeamPoint); + } + private static void playGame(Command moveCommand, ChessGame chessGame) { List options = moveCommand.getOptions(); Position from = options.get(0); diff --git a/src/main/java/chess/domain/board/ChessBoardWrapper.java b/src/main/java/chess/domain/board/ChessBoardWrapper.java index 192da8a099a..4b09eebe52f 100644 --- a/src/main/java/chess/domain/board/ChessBoardWrapper.java +++ b/src/main/java/chess/domain/board/ChessBoardWrapper.java @@ -2,6 +2,7 @@ import chess.domain.Position; import chess.domain.piece.Piece; +import chess.domain.piece.Team; import java.util.List; public class ChessBoardWrapper { @@ -18,4 +19,8 @@ public boolean move(Position from, Position to) { public List getPiecesOnBoard() { return chessBoard.getPiecesOnBoard(); } + + public double calculatePoint(Team team) { + return chessBoard.calculatePoint(team); + } } diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 929ef2c2e46..77ca6a44ef6 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -4,6 +4,7 @@ import chess.domain.board.ChessBoard; import chess.domain.board.ChessBoardWrapper; import chess.domain.piece.Piece; +import chess.domain.piece.Team; import java.util.List; public class ChessGame { @@ -17,6 +18,10 @@ public boolean move(Position from, Position to) { return chessBoardWrapper.move(from, to); } + public double calculatePoint(Team team) { + return chessBoardWrapper.calculatePoint(team); + } + public List getPiecesOnBoard() { return chessBoardWrapper.getPiecesOnBoard(); } diff --git a/src/main/java/chess/domain/game/StatusCommand.java b/src/main/java/chess/domain/game/StatusCommand.java new file mode 100644 index 00000000000..3c01a4d9de1 --- /dev/null +++ b/src/main/java/chess/domain/game/StatusCommand.java @@ -0,0 +1,20 @@ +package chess.domain.game; + +import java.util.List; + +public class StatusCommand extends Command { + public static final StatusCommand STATUS_COMMAND = new StatusCommand(); + + private StatusCommand() { + this(null); + } + + private StatusCommand(String[] options) { + super(options); + } + + @Override + public List getOptions() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java index ffe811b905c..7142a98c13d 100644 --- a/src/main/java/chess/view/InputView.java +++ b/src/main/java/chess/view/InputView.java @@ -4,6 +4,7 @@ import chess.domain.game.EndCommand; import chess.domain.game.MoveCommand; import chess.domain.game.StartCommand; +import chess.domain.game.StatusCommand; import java.util.Scanner; public class InputView { @@ -46,4 +47,26 @@ public static Command readEndOrMove() { String[] splitOptions = options.split(SEPARATOR); return new MoveCommand(splitOptions); } + + public static Command readEndOrMoveOrStatus() { + Scanner scanner = new Scanner(System.in); + String input = scanner.nextLine(); + while (!input.matches("move [a-h][1-8] [a-h][1-8]") && !isEndCommand(input) && !isStatusCommand(input)) { + System.out.println("다시 입력해 주세요"); + input = scanner.nextLine(); + } + if (isEndCommand(input)) { + return EndCommand.END_COMMAND; + } + if (isStatusCommand(input)) { + return StatusCommand.STATUS_COMMAND; + } + String options = input.substring(OPTION_BEGIN_INDEX); + String[] splitOptions = options.split(SEPARATOR); + return new MoveCommand(splitOptions); + } + + private static boolean isStatusCommand(String input) { + return input.equals("status"); + } } diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index 84d561d2264..78fc0178258 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -44,6 +44,10 @@ public static void printReInputGuide() { System.out.println("다시 입력해 주세요"); } + public static void printStatus(Team team, double point) { + System.out.printf("%s: %f%n", team.name(), point); + } + enum PieceAsset { BLACK_KING('K'), BLACK_QUEEN('Q'), From 21e862d2036b079a44b8b6abcfff962c37d42f6e Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 22:39:38 +0900 Subject: [PATCH 06/45] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9806d56f595..4db1e0d91cf 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ - [x] 체스 보드 - [x] 올바른 턴인지 확인한다 - [x] 잡힌 말을 제거한다 +- [ ] 종료 조건 + - [ ] 킹이 잡히면 게임이 종료되는 기능 - [x] 점수 - [x] 각 말의 점수 계산 기능 - [x] 폰의 점수 보정 기능 From 1555f411c10080b6150367a834482bab6cdbfb23 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 23:41:45 +0900 Subject: [PATCH 07/45] =?UTF-8?q?feat:=20=EC=A2=85=EB=A3=8C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- src/main/java/chess/Application.java | 42 +++++++++++-------- .../java/chess/domain/board/ChessBoard.java | 22 ++++++++++ .../chess/domain/board/ChessBoardWrapper.java | 5 ++- .../java/chess/domain/game/ChessGame.java | 3 +- .../chess/domain/piece/PieceMoveResult.java | 6 ++- src/main/java/chess/view/InputView.java | 15 ------- src/main/java/chess/view/OutputView.java | 11 +++++ 8 files changed, 70 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 4db1e0d91cf..1c4fe9e057a 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ - [x] 체스 보드 - [x] 올바른 턴인지 확인한다 - [x] 잡힌 말을 제거한다 -- [ ] 종료 조건 - - [ ] 킹이 잡히면 게임이 종료되는 기능 +- [x] 종료 조건 + - [x] 킹이 잡히면 게임이 종료되는 기능 - [x] 점수 - [x] 각 말의 점수 계산 기능 - [x] 폰의 점수 보정 기능 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index c220162e5ec..0f381be1ebd 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -7,6 +7,7 @@ import chess.domain.game.Command; import chess.domain.game.StatusCommand; import chess.domain.piece.Piece; +import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; import chess.domain.piece.Team; import chess.dto.PieceDTO; @@ -26,11 +27,12 @@ public static void main(String[] args) { List pieceDTOS = piecesToDTO(piecesOnBoard); OutputView.printChessBoard(pieceDTOS); - Command endOrMoveOrStatus = InputView.readEndOrMoveOrStatus(); - while (!isEndCommand(endOrMoveOrStatus)) { - playGameOrPrintStatus(endOrMoveOrStatus, chessGame); + Command endOrMoveOrStatus; + PieceMoveResult pieceMoveResult; + do { endOrMoveOrStatus = InputView.readEndOrMoveOrStatus(); - } + pieceMoveResult = playGameOrPrintStatus(endOrMoveOrStatus, chessGame); + } while (!isEndCommand(endOrMoveOrStatus) && !pieceMoveResult.isEnd()); } private static List piecesToDTO(List piecesOnBoard) { @@ -47,31 +49,37 @@ private static boolean isEndCommand(Command command) { return command.equals(END_COMMAND); } - private static void playGameOrPrintStatus(Command moveOrStatus, ChessGame chessGame) { + private static PieceMoveResult playGameOrPrintStatus(Command moveOrStatus, ChessGame chessGame) { if (moveOrStatus.equals(StatusCommand.STATUS_COMMAND)) { printStatus(chessGame); - return; + return PieceMoveResult.FAILURE; } - playGame(moveOrStatus, chessGame); - } - - private static void printStatus(ChessGame chessGame) { - double whiteTeamPoint = chessGame.calculatePoint(Team.WHITE); - OutputView.printStatus(Team.WHITE, whiteTeamPoint); - double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); - OutputView.printStatus(Team.BLACK, blackTeamPoint); + return playGame(moveOrStatus, chessGame); } - private static void playGame(Command moveCommand, ChessGame chessGame) { + private static PieceMoveResult playGame(Command moveCommand, ChessGame chessGame) { List options = moveCommand.getOptions(); Position from = options.get(0); Position to = options.get(1); - boolean moveSuccess = chessGame.move(from, to); + PieceMoveResult moveResult = chessGame.move(from, to); List piecesOnBoard = chessGame.getPiecesOnBoard(); List pieceDTOS = piecesToDTO(piecesOnBoard); OutputView.printChessBoard(pieceDTOS); - if (!moveSuccess) { + printReInputGuideIfNeed(moveResult); + OutputView.printWinner(moveResult); + return moveResult; + } + + private static void printReInputGuideIfNeed(PieceMoveResult moveResult) { + if (moveResult.equals(PieceMoveResult.FAILURE)) { OutputView.printReInputGuide(); } } + + private static void printStatus(ChessGame chessGame) { + double whiteTeamPoint = chessGame.calculatePoint(Team.WHITE); + OutputView.printStatus(Team.WHITE, whiteTeamPoint); + double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); + OutputView.printStatus(Team.BLACK, blackTeamPoint); + } } diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index e5ba25f617c..700fbfb4603 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -85,6 +85,28 @@ private void changeCurrentTeamIfNotFail(PieceMoveResult moveResult) { } } + PieceMoveResult move2(Position from, Position to) { + if (isEmptyPosition(from) || isOtherTeamTurn(from)) { + return PieceMoveResult.FAILURE; + } + Piece piece = findPiece(from); + PieceMoveResult moveResult = piece.move(to, this); + if (moveResult.equals(PieceMoveResult.CATCH)) { + boolean isGameOver = piecesOnBoard.stream().filter(piece1 -> piece1.getPieceType().equals(PieceType.KING)) + .filter(piece1 -> piece1.getTeam().equals(currentTeam.otherTeam())) + .allMatch(piece1 -> piece1.isOn(to)); + if (isGameOver && currentTeam.equals(Team.WHITE)) { + return PieceMoveResult.WHITE_WIN; + } + if (isGameOver && currentTeam.equals(Team.BLACK)) { + return PieceMoveResult.BLACK_WIN; + } + } + removePieceIfCaught(to, moveResult); + changeCurrentTeamIfNotFail(moveResult); + return moveResult; + } + public Optional whichTeam(Position position) { Optional pieceOnPosition = piecesOnBoard.stream().filter(piece -> piece.isOn(position)) .findFirst(); diff --git a/src/main/java/chess/domain/board/ChessBoardWrapper.java b/src/main/java/chess/domain/board/ChessBoardWrapper.java index 4b09eebe52f..661f616cd32 100644 --- a/src/main/java/chess/domain/board/ChessBoardWrapper.java +++ b/src/main/java/chess/domain/board/ChessBoardWrapper.java @@ -2,6 +2,7 @@ import chess.domain.Position; import chess.domain.piece.Piece; +import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; @@ -12,8 +13,8 @@ public ChessBoardWrapper(ChessBoard chessBoard) { this.chessBoard = chessBoard; } - public boolean move(Position from, Position to) { - return chessBoard.move(from, to); + public PieceMoveResult move(Position from, Position to) { + return chessBoard.move2(from, to); } public List getPiecesOnBoard() { diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 77ca6a44ef6..2ee933bb3ad 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -4,6 +4,7 @@ import chess.domain.board.ChessBoard; import chess.domain.board.ChessBoardWrapper; import chess.domain.piece.Piece; +import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; @@ -14,7 +15,7 @@ public ChessGame() { this.chessBoardWrapper = new ChessBoardWrapper(new ChessBoard()); } - public boolean move(Position from, Position to) { + public PieceMoveResult move(Position from, Position to) { return chessBoardWrapper.move(from, to); } diff --git a/src/main/java/chess/domain/piece/PieceMoveResult.java b/src/main/java/chess/domain/piece/PieceMoveResult.java index 751faa59d26..7130d8c0c9f 100644 --- a/src/main/java/chess/domain/piece/PieceMoveResult.java +++ b/src/main/java/chess/domain/piece/PieceMoveResult.java @@ -1,9 +1,13 @@ package chess.domain.piece; public enum PieceMoveResult { - SUCCESS, FAILURE, CATCH; + SUCCESS, FAILURE, CATCH, WHITE_WIN, BLACK_WIN; public boolean toBoolean() { return !this.equals(FAILURE); } + + public boolean isEnd() { + return this.equals(BLACK_WIN) || this.equals(WHITE_WIN); + } } diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java index 7142a98c13d..82d5b0165a5 100644 --- a/src/main/java/chess/view/InputView.java +++ b/src/main/java/chess/view/InputView.java @@ -33,21 +33,6 @@ private static boolean isEndCommand(String input) { return input.equals("end"); } - public static Command readEndOrMove() { - Scanner scanner = new Scanner(System.in); - String input = scanner.nextLine(); - while (!input.matches("move [a-h][1-8] [a-h][1-8]") && !isEndCommand(input)) { - System.out.println("다시 입력해 주세요"); - input = scanner.nextLine(); - } - if (isEndCommand(input)) { - return EndCommand.END_COMMAND; - } - String options = input.substring(OPTION_BEGIN_INDEX); - String[] splitOptions = options.split(SEPARATOR); - return new MoveCommand(splitOptions); - } - public static Command readEndOrMoveOrStatus() { Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index 78fc0178258..127d87f8b2e 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -1,5 +1,6 @@ package chess.view; +import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; import chess.domain.piece.Team; import chess.dto.PieceDTO; @@ -48,6 +49,16 @@ public static void printStatus(Team team, double point) { System.out.printf("%s: %f%n", team.name(), point); } + public static void printWinner(PieceMoveResult pieceMoveResult) { + if (pieceMoveResult.equals(PieceMoveResult.BLACK_WIN)) { + System.out.println("BLACK 승리"); + return; + } + if (pieceMoveResult.equals(PieceMoveResult.WHITE_WIN)) { + System.out.println("WHITE 승리"); + } + } + enum PieceAsset { BLACK_KING('K'), BLACK_QUEEN('Q'), From f53bdaddeeedfdcb10f7268311b5f280e9aa274b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 25 Mar 2024 23:47:43 +0900 Subject: [PATCH 08/45] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20todo?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/chess/domain/board/ChessBoard.java | 39 +++++++------------ .../chess/domain/board/ChessBoardWrapper.java | 2 +- .../chess/domain/piece/PieceMoveResult.java | 7 +--- .../chess/domain/board/ChessBoardTest.java | 27 +++++++------ 4 files changed, 32 insertions(+), 43 deletions(-) diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index 700fbfb4603..1db24e46c39 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -30,15 +30,26 @@ public ChessBoard(Piece... pieces) { this(List.of(pieces)); } - boolean move(Position from, Position to) { + PieceMoveResult move(Position from, Position to) { if (isEmptyPosition(from) || isOtherTeamTurn(from)) { - return false; + return PieceMoveResult.FAILURE; } Piece piece = findPiece(from); PieceMoveResult moveResult = piece.move(to, this); + if (moveResult.equals(PieceMoveResult.CATCH)) { + boolean isGameOver = piecesOnBoard.stream().filter(piece1 -> piece1.getPieceType().equals(PieceType.KING)) + .filter(piece1 -> piece1.getTeam().equals(currentTeam.otherTeam())) + .allMatch(piece1 -> piece1.isOn(to)); + if (isGameOver && currentTeam.equals(Team.WHITE)) { + return PieceMoveResult.WHITE_WIN; + } + if (isGameOver && currentTeam.equals(Team.BLACK)) { + return PieceMoveResult.BLACK_WIN; + } + } removePieceIfCaught(to, moveResult); changeCurrentTeamIfNotFail(moveResult); - return moveResult.toBoolean(); + return moveResult; } private boolean isEmptyPosition(Position from) { @@ -85,28 +96,6 @@ private void changeCurrentTeamIfNotFail(PieceMoveResult moveResult) { } } - PieceMoveResult move2(Position from, Position to) { - if (isEmptyPosition(from) || isOtherTeamTurn(from)) { - return PieceMoveResult.FAILURE; - } - Piece piece = findPiece(from); - PieceMoveResult moveResult = piece.move(to, this); - if (moveResult.equals(PieceMoveResult.CATCH)) { - boolean isGameOver = piecesOnBoard.stream().filter(piece1 -> piece1.getPieceType().equals(PieceType.KING)) - .filter(piece1 -> piece1.getTeam().equals(currentTeam.otherTeam())) - .allMatch(piece1 -> piece1.isOn(to)); - if (isGameOver && currentTeam.equals(Team.WHITE)) { - return PieceMoveResult.WHITE_WIN; - } - if (isGameOver && currentTeam.equals(Team.BLACK)) { - return PieceMoveResult.BLACK_WIN; - } - } - removePieceIfCaught(to, moveResult); - changeCurrentTeamIfNotFail(moveResult); - return moveResult; - } - public Optional whichTeam(Position position) { Optional pieceOnPosition = piecesOnBoard.stream().filter(piece -> piece.isOn(position)) .findFirst(); diff --git a/src/main/java/chess/domain/board/ChessBoardWrapper.java b/src/main/java/chess/domain/board/ChessBoardWrapper.java index 661f616cd32..fa3442aeecd 100644 --- a/src/main/java/chess/domain/board/ChessBoardWrapper.java +++ b/src/main/java/chess/domain/board/ChessBoardWrapper.java @@ -14,7 +14,7 @@ public ChessBoardWrapper(ChessBoard chessBoard) { } public PieceMoveResult move(Position from, Position to) { - return chessBoard.move2(from, to); + return chessBoard.move(from, to); } public List getPiecesOnBoard() { diff --git a/src/main/java/chess/domain/piece/PieceMoveResult.java b/src/main/java/chess/domain/piece/PieceMoveResult.java index 7130d8c0c9f..1a5500a89bb 100644 --- a/src/main/java/chess/domain/piece/PieceMoveResult.java +++ b/src/main/java/chess/domain/piece/PieceMoveResult.java @@ -1,12 +1,9 @@ package chess.domain.piece; public enum PieceMoveResult { + //Todo 게임 종료 여부 분리 SUCCESS, FAILURE, CATCH, WHITE_WIN, BLACK_WIN; - - public boolean toBoolean() { - return !this.equals(FAILURE); - } - + public boolean isEnd() { return this.equals(BLACK_WIN) || this.equals(WHITE_WIN); } diff --git a/src/test/java/chess/domain/board/ChessBoardTest.java b/src/test/java/chess/domain/board/ChessBoardTest.java index 1371764df9f..ca4a847198c 100644 --- a/src/test/java/chess/domain/board/ChessBoardTest.java +++ b/src/test/java/chess/domain/board/ChessBoardTest.java @@ -24,6 +24,8 @@ import static chess.domain.Position.E3; import static chess.domain.Position.F2; import static chess.domain.Position.H1; +import static chess.domain.piece.PieceMoveResult.FAILURE; +import static chess.domain.piece.PieceMoveResult.SUCCESS; import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; import static org.junit.jupiter.api.Assertions.assertAll; @@ -34,6 +36,7 @@ import chess.domain.piece.Knight; import chess.domain.piece.Pawn; import chess.domain.piece.Piece; +import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Queen; import chess.domain.piece.Rook; import chess.domain.piece.Team; @@ -78,8 +81,8 @@ public static Stream whichTeamParameters() { void moveSuccess(Position from, Position to) { ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Rook(A1, WHITE), new King(E1, WHITE), new Knight(B1, WHITE), new Bishop(C1, WHITE), new Queen(D1, WHITE)); - boolean moveSuccess = chessBoard.move(from, to); - Assertions.assertThat(moveSuccess).isTrue(); + PieceMoveResult moveResult = chessBoard.move(from, to); + Assertions.assertThat(moveResult).isEqualTo(SUCCESS); } @ParameterizedTest @@ -88,16 +91,16 @@ void moveSuccess(Position from, Position to) { void moveFailureCauseInvalidMove(Position from, Position to) { ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Rook(A1, WHITE), new King(E1, WHITE), new Knight(B1, WHITE), new Bishop(C1, WHITE), new Queen(D1, WHITE)); - boolean moveSuccess = chessBoard.move(from, to); - Assertions.assertThat(moveSuccess).isFalse(); + PieceMoveResult moveResult = chessBoard.move(from, to); + Assertions.assertThat(moveResult).isEqualTo(FAILURE); } @Test @DisplayName("해당 위치에 말이 없어서 이동이 실패하는지 검증") void moveFailureCausePieceNotFound() { ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE)); - boolean moveSuccess = chessBoard.move(D3, D4); - Assertions.assertThat(moveSuccess).isFalse(); + PieceMoveResult moveResult = chessBoard.move(D3, D4); + Assertions.assertThat(moveResult).isEqualTo(FAILURE); } @Test @@ -106,8 +109,8 @@ void moveFailureCauseInvalidTurn() { ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Pawn(D7, BLACK)); chessBoard.move(D2, D4); - boolean moveSuccess = chessBoard.move(D4, D5); - Assertions.assertThat(moveSuccess).isFalse(); + PieceMoveResult moveResult = chessBoard.move(D4, D5); + Assertions.assertThat(moveResult).isEqualTo(FAILURE); } @Test @@ -126,8 +129,8 @@ void catchSuccess() { void validateTurnNotChangeWhenInvalidMove() { ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Pawn(C3, BLACK)); chessBoard.move(D2, D8); - boolean blackMoveSuccess = chessBoard.move(C3, C2); - Assertions.assertThat(blackMoveSuccess).isFalse(); + PieceMoveResult moveResult = chessBoard.move(C3, C2); + Assertions.assertThat(moveResult).isEqualTo(FAILURE); } @Test @@ -135,8 +138,8 @@ void validateTurnNotChangeWhenInvalidMove() { void validateTurnChangeWhenValidMove() { ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Pawn(C3, BLACK)); chessBoard.move(D2, D3); - boolean blackMoveSuccess = chessBoard.move(C3, C2); - Assertions.assertThat(blackMoveSuccess).isTrue(); + PieceMoveResult moveResult = chessBoard.move(C3, C2); + Assertions.assertThat(moveResult).isEqualTo(SUCCESS); } @ParameterizedTest From a1e44b40f65d75412819c67f1b841efd20a5593b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 11:07:07 +0900 Subject: [PATCH 09/45] =?UTF-8?q?refactor:=20=EA=B0=81=20=ED=8C=80?= =?UTF-8?q?=EC=9D=98=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=EB=A5=BC=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=ED=95=98=EB=8A=94=20=EC=B1=85=EC=9E=84=EC=9D=84=20Che?= =?UTF-8?q?ssBoard=20=EB=A1=9C=EB=B6=80=ED=84=B0=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/chess/domain/board/ChessBoard.java | 34 +------------- .../chess/domain/board/PointCalculator.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 33 deletions(-) create mode 100644 src/main/java/chess/domain/board/PointCalculator.java diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index 1db24e46c39..fae518d7255 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -10,9 +10,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; public class ChessBoard { private final List piecesOnBoard; @@ -107,36 +105,6 @@ List getPiecesOnBoard() { } double calculatePoint(Team team) { - double totalPoint = calculateWithOutSameColumnPawn(team); - Map> pawnsAtSameColumn = pawnGroupingByColumn(team); - double correctionPoint = calculatePawnCorrectionPoint(pawnsAtSameColumn); - return totalPoint - correctionPoint; - } - - private double calculateWithOutSameColumnPawn(Team team) { - return piecesOnBoard.stream() - .filter(piece -> piece.isTeamWith(team)) - .mapToDouble(Piece::getPoint) - .reduce(0.0, Double::sum); - } - - private Map> pawnGroupingByColumn(Team team) { - return piecesOnBoard.stream() - .filter(piece -> piece.isTeamWith(team)) - .filter(this::isPawn) - .collect(Collectors.groupingBy(Piece::getColumn, Collectors.toUnmodifiableList())); - } - - private boolean isPawn(Piece piece) { - PieceType pieceType = piece.getPieceType(); - return pieceType.equals(PieceType.PAWN); - } - - private double calculatePawnCorrectionPoint(Map> pawnsAtSameColumn) { - final double correctionPointPerPawn = 0.5; - return pawnsAtSameColumn.values().stream() - .filter(pieces -> pieces.size() > 1) - .mapToDouble(pieces -> pieces.size() * correctionPointPerPawn) - .reduce(0.0, Double::sum); + return PointCalculator.calculatePoint(team, piecesOnBoard); } } diff --git a/src/main/java/chess/domain/board/PointCalculator.java b/src/main/java/chess/domain/board/PointCalculator.java new file mode 100644 index 00000000000..ce51cbaeda6 --- /dev/null +++ b/src/main/java/chess/domain/board/PointCalculator.java @@ -0,0 +1,46 @@ +package chess.domain.board; + +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.domain.piece.Team; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +class PointCalculator { + static double calculatePoint(Team team, List piecesOnBoard) { + piecesOnBoard = Collections.unmodifiableList(piecesOnBoard); + double totalPoint = calculateWithOutSameColumnPawn(team, piecesOnBoard); + Map> pawnsAtSameColumn = pawnGroupingByColumn(team, piecesOnBoard); + double correctionPoint = calculatePawnCorrectionPoint(pawnsAtSameColumn); + return totalPoint - correctionPoint; + } + + private static double calculateWithOutSameColumnPawn(Team team, List piecesOnBoard) { + return piecesOnBoard.stream() + .filter(piece -> piece.isTeamWith(team)) + .mapToDouble(Piece::getPoint) + .reduce(0.0, Double::sum); + } + + private static Map> pawnGroupingByColumn(Team team, List piecesOnBoard) { + return piecesOnBoard.stream() + .filter(piece -> piece.isTeamWith(team)) + .filter(PointCalculator::isPawn) + .collect(Collectors.groupingBy(Piece::getColumn, Collectors.toUnmodifiableList())); + } + + private static boolean isPawn(Piece piece) { + PieceType pieceType = piece.getPieceType(); + return pieceType.equals(PieceType.PAWN); + } + + private static double calculatePawnCorrectionPoint(Map> pawnsAtSameColumn) { + final double correctionPointPerPawn = 0.5; + return pawnsAtSameColumn.values().stream() + .filter(pieces -> pieces.size() > 1) + .mapToDouble(pieces -> pieces.size() * correctionPointPerPawn) + .reduce(0.0, Double::sum); + } +} From ab168a57fdfc9bbf741fae062746580d219e5c4f Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 11:26:51 +0900 Subject: [PATCH 10/45] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?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 --- .../java/chess/domain/board/ChessBoard.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index fae518d7255..9dc3f868db2 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -34,22 +34,38 @@ PieceMoveResult move(Position from, Position to) { } Piece piece = findPiece(from); PieceMoveResult moveResult = piece.move(to, this); - if (moveResult.equals(PieceMoveResult.CATCH)) { - boolean isGameOver = piecesOnBoard.stream().filter(piece1 -> piece1.getPieceType().equals(PieceType.KING)) - .filter(piece1 -> piece1.getTeam().equals(currentTeam.otherTeam())) - .allMatch(piece1 -> piece1.isOn(to)); - if (isGameOver && currentTeam.equals(Team.WHITE)) { - return PieceMoveResult.WHITE_WIN; - } - if (isGameOver && currentTeam.equals(Team.BLACK)) { - return PieceMoveResult.BLACK_WIN; - } - } + moveResult = fixMoveResultWhenGameEnd(to, moveResult); removePieceIfCaught(to, moveResult); changeCurrentTeamIfNotFail(moveResult); return moveResult; } + private PieceMoveResult fixMoveResultWhenGameEnd(Position to, PieceMoveResult moveResult) { + boolean gameEnd = isGameEnd(to); + if (gameEnd && currentTeam.equals(Team.WHITE)) { + return PieceMoveResult.WHITE_WIN; + } + if (gameEnd && currentTeam.equals(Team.BLACK)) { + return PieceMoveResult.BLACK_WIN; + } + return moveResult; + } + + private boolean isGameEnd(Position to) { + return piecesOnBoard.stream() + .filter(this::isKing) + .filter(this::isOtherTeam) + .allMatch(piece -> piece.isOn(to)); + } + + private boolean isKing(Piece piece) { + return piece.getPieceType().equals(PieceType.KING); + } + + private boolean isOtherTeam(Piece piece) { + return piece.isTeamWith(currentTeam.otherTeam()); + } + private boolean isEmptyPosition(Position from) { Optional optionalPiece = piecesOnBoard.stream() .filter(piece -> piece.isOn(from)) @@ -79,11 +95,7 @@ private void removePieceIfCaught(Position to, PieceMoveResult moveResult) { private void removeDeadPiece(Position to) { Piece needToRemovePiece = piecesOnBoard.stream() .filter(piece -> piece.isOn(to)) - .filter(piece -> { - Team pieceTeam = piece.getTeam(); - Team otherTeam = currentTeam.otherTeam(); - return pieceTeam.equals(otherTeam); - }) + .filter(this::isOtherTeam) .findFirst().orElseThrow(); piecesOnBoard.remove(needToRemovePiece); } From b7a964154ac66f5296f0b8bf986ea3e925d0f8d0 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 11:32:57 +0900 Subject: [PATCH 11/45] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?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/chess/Application.java | 49 ++++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 0f381be1ebd..505930d6de5 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -22,17 +22,21 @@ public static void main(String[] args) { if (isEndCommand(startOrEnd)) { return; } + ChessGame chessGame = new ChessGame(); + printPiecesOnChessBoard(chessGame); + + playChess(chessGame); + } + + private static boolean isEndCommand(Command command) { + return command.equals(END_COMMAND); + } + + private static void printPiecesOnChessBoard(ChessGame chessGame) { List piecesOnBoard = chessGame.getPiecesOnBoard(); List pieceDTOS = piecesToDTO(piecesOnBoard); OutputView.printChessBoard(pieceDTOS); - - Command endOrMoveOrStatus; - PieceMoveResult pieceMoveResult; - do { - endOrMoveOrStatus = InputView.readEndOrMoveOrStatus(); - pieceMoveResult = playGameOrPrintStatus(endOrMoveOrStatus, chessGame); - } while (!isEndCommand(endOrMoveOrStatus) && !pieceMoveResult.isEnd()); } private static List piecesToDTO(List piecesOnBoard) { @@ -45,8 +49,13 @@ private static List piecesToDTO(List piecesOnBoard) { }).toList(); } - private static boolean isEndCommand(Command command) { - return command.equals(END_COMMAND); + private static void playChess(ChessGame chessGame) { + Command endOrMoveOrStatus; + PieceMoveResult pieceMoveResult; + do { + endOrMoveOrStatus = InputView.readEndOrMoveOrStatus(); + pieceMoveResult = playGameOrPrintStatus(endOrMoveOrStatus, chessGame); + } while (!isEndCommand(endOrMoveOrStatus) && !pieceMoveResult.isEnd()); } private static PieceMoveResult playGameOrPrintStatus(Command moveOrStatus, ChessGame chessGame) { @@ -57,16 +66,21 @@ private static PieceMoveResult playGameOrPrintStatus(Command moveOrStatus, Chess return playGame(moveOrStatus, chessGame); } + private static void printStatus(ChessGame chessGame) { + double whiteTeamPoint = chessGame.calculatePoint(Team.WHITE); + OutputView.printStatus(Team.WHITE, whiteTeamPoint); + double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); + OutputView.printStatus(Team.BLACK, blackTeamPoint); + } + private static PieceMoveResult playGame(Command moveCommand, ChessGame chessGame) { List options = moveCommand.getOptions(); Position from = options.get(0); Position to = options.get(1); PieceMoveResult moveResult = chessGame.move(from, to); - List piecesOnBoard = chessGame.getPiecesOnBoard(); - List pieceDTOS = piecesToDTO(piecesOnBoard); - OutputView.printChessBoard(pieceDTOS); + printPiecesOnChessBoard(chessGame); printReInputGuideIfNeed(moveResult); - OutputView.printWinner(moveResult); + printWinnerIfNeed(moveResult); return moveResult; } @@ -76,10 +90,9 @@ private static void printReInputGuideIfNeed(PieceMoveResult moveResult) { } } - private static void printStatus(ChessGame chessGame) { - double whiteTeamPoint = chessGame.calculatePoint(Team.WHITE); - OutputView.printStatus(Team.WHITE, whiteTeamPoint); - double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); - OutputView.printStatus(Team.BLACK, blackTeamPoint); + private static void printWinnerIfNeed(PieceMoveResult moveResult) { + if (moveResult.isEnd()) { + OutputView.printWinner(moveResult); + } } } From 1ecd8713c2b40e8303e62976badfea3a37407e54 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 11:56:02 +0900 Subject: [PATCH 12/45] =?UTF-8?q?test:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chess/domain/board/ChessBoardTest.java | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/test/java/chess/domain/board/ChessBoardTest.java b/src/test/java/chess/domain/board/ChessBoardTest.java index ca4a847198c..1854abfb7b4 100644 --- a/src/test/java/chess/domain/board/ChessBoardTest.java +++ b/src/test/java/chess/domain/board/ChessBoardTest.java @@ -6,6 +6,7 @@ import static chess.domain.Position.A4; import static chess.domain.Position.A5; import static chess.domain.Position.A6; +import static chess.domain.Position.A8; import static chess.domain.Position.B1; import static chess.domain.Position.B2; import static chess.domain.Position.B6; @@ -24,6 +25,7 @@ import static chess.domain.Position.E3; import static chess.domain.Position.F2; import static chess.domain.Position.H1; +import static chess.domain.Position.H2; import static chess.domain.piece.PieceMoveResult.FAILURE; import static chess.domain.piece.PieceMoveResult.SUCCESS; import static chess.domain.piece.Team.BLACK; @@ -62,7 +64,7 @@ public static Stream moveSuccessParameters() { public static Stream moveFailureCauseInvalidMoveParameters() { return Stream.of( - Arguments.of(D2, D5), Arguments.of(D2, C3), Arguments.of(A1, H1), Arguments.of(A1, B6), + Arguments.of(D2, D5), Arguments.of(D2, C3), Arguments.of(A1, H2), Arguments.of(A1, B6), Arguments.of(B1, B2), Arguments.of(C1, C6), Arguments.of(D1, D3), Arguments.of(D1, C3), Arguments.of(E1, E3) ); @@ -79,7 +81,8 @@ public static Stream whichTeamParameters() { @MethodSource("moveSuccessParameters") @DisplayName("정상적인 경우에 이동이 성공하는지 검증") void moveSuccess(Position from, Position to) { - ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Rook(A1, WHITE), new King(E1, WHITE), + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(D2, WHITE), + new Rook(A1, WHITE), new King(E1, WHITE), new Knight(B1, WHITE), new Bishop(C1, WHITE), new Queen(D1, WHITE)); PieceMoveResult moveResult = chessBoard.move(from, to); Assertions.assertThat(moveResult).isEqualTo(SUCCESS); @@ -89,7 +92,8 @@ void moveSuccess(Position from, Position to) { @MethodSource("moveFailureCauseInvalidMoveParameters") @DisplayName("해당 위치가 이동이 불가능한 위치라서 이동이 실패하는지 검증") void moveFailureCauseInvalidMove(Position from, Position to) { - ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Rook(A1, WHITE), new King(E1, WHITE), + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(D2, WHITE), + new Rook(A1, WHITE), new King(E1, WHITE), new Knight(B1, WHITE), new Bishop(C1, WHITE), new Queen(D1, WHITE)); PieceMoveResult moveResult = chessBoard.move(from, to); Assertions.assertThat(moveResult).isEqualTo(FAILURE); @@ -98,7 +102,7 @@ void moveFailureCauseInvalidMove(Position from, Position to) { @Test @DisplayName("해당 위치에 말이 없어서 이동이 실패하는지 검증") void moveFailureCausePieceNotFound() { - ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE)); + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(D2, WHITE)); PieceMoveResult moveResult = chessBoard.move(D3, D4); Assertions.assertThat(moveResult).isEqualTo(FAILURE); } @@ -106,7 +110,8 @@ void moveFailureCausePieceNotFound() { @Test @DisplayName("팀의 이동 차례가 아니라서 이동이 실패하는지 검증") void moveFailureCauseInvalidTurn() { - ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Pawn(D7, BLACK)); + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(D2, WHITE), + new Pawn(D7, BLACK)); chessBoard.move(D2, D4); PieceMoveResult moveResult = chessBoard.move(D4, D5); @@ -117,17 +122,20 @@ void moveFailureCauseInvalidTurn() { @DisplayName("상대 말을 잡으면 그 말이 보드에서 사라지는지 검증") void catchSuccess() { Pawn survivor = new Pawn(D2, WHITE); - ChessBoard chessBoard = new ChessBoard(survivor, new Pawn(C3, BLACK)); + King whiteKing = new King(A8, WHITE); + King blackKing = new King(H1, BLACK); + ChessBoard chessBoard = new ChessBoard(whiteKing, blackKing, survivor, new Pawn(C3, BLACK)); chessBoard.move(D2, C3); List piecesOnBoard = chessBoard.getPiecesOnBoard(); Assertions.assertThat(piecesOnBoard) - .containsExactly(survivor); + .containsExactly(whiteKing, blackKing, survivor); } @Test @DisplayName("잘못된 이동을 시도했을 때 차례가 넘어가지 않는지 검증") void validateTurnNotChangeWhenInvalidMove() { - ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Pawn(C3, BLACK)); + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(D2, WHITE), + new Pawn(C3, BLACK)); chessBoard.move(D2, D8); PieceMoveResult moveResult = chessBoard.move(C3, C2); Assertions.assertThat(moveResult).isEqualTo(FAILURE); @@ -136,7 +144,8 @@ void validateTurnNotChangeWhenInvalidMove() { @Test @DisplayName("이동이 성공했을 때 차례가 넘어가는지 검증") void validateTurnChangeWhenValidMove() { - ChessBoard chessBoard = new ChessBoard(new Pawn(D2, WHITE), new Pawn(C3, BLACK)); + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(D2, WHITE), + new Pawn(C3, BLACK)); chessBoard.move(D2, D3); PieceMoveResult moveResult = chessBoard.move(C3, C2); Assertions.assertThat(moveResult).isEqualTo(SUCCESS); @@ -156,7 +165,7 @@ void whichTeam(Team team) { @Test @DisplayName("해당 위치에 말이 없는 경우 팀을 판단할 수 없는지 검증") void whichTeamWhenEmpty() { - ChessBoard chessBoard = new ChessBoard(List.of()); + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK)); Optional actual = chessBoard.whichTeam(D2); Assertions.assertThat(actual) .isEmpty(); @@ -178,7 +187,8 @@ void calculatePoint() { @Test @DisplayName("같은 열의 폰이 포함된 각 팀의 점수가 잘 계산되는지 검증") void calculatePointWithPawn() { - ChessBoard chessBoard = new ChessBoard(new Pawn(A2, BLACK), new Pawn(B2, BLACK), new Pawn(A3, BLACK), + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(A2, BLACK), + new Pawn(B2, BLACK), new Pawn(A3, BLACK), new Pawn(A4, WHITE), new Pawn(A5, WHITE), new Pawn(A6, WHITE)); double whiteTeamPoint = chessBoard.calculatePoint(WHITE); double blackTeamPoint = chessBoard.calculatePoint(BLACK); From 4c3c8468cd99b21368856de88ad108045ada2d7c Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 12:07:24 +0900 Subject: [PATCH 13/45] =?UTF-8?q?feat:=20=EC=A0=90=EC=88=98=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EC=8B=9C=20=ED=98=84=EC=9E=AC=20=EC=9D=B4=EA=B8=B0?= =?UTF-8?q?=EA=B3=A0=20=EC=9E=88=EB=8A=94=20=ED=8C=80=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=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/chess/Application.java | 1 + src/main/java/chess/view/OutputView.java | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 505930d6de5..317d1416497 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -71,6 +71,7 @@ private static void printStatus(ChessGame chessGame) { OutputView.printStatus(Team.WHITE, whiteTeamPoint); double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); OutputView.printStatus(Team.BLACK, blackTeamPoint); + OutputView.currentWinner(whiteTeamPoint, blackTeamPoint); } private static PieceMoveResult playGame(Command moveCommand, ChessGame chessGame) { diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index 127d87f8b2e..f4194a0aadb 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -59,6 +59,18 @@ public static void printWinner(PieceMoveResult pieceMoveResult) { } } + public static void currentWinner(double whitePoint, double blackPoint) { + if (blackPoint > whitePoint) { + System.out.println("BLACK이 이기는 중"); + return; + } + if (whitePoint > blackPoint) { + System.out.println("WHITE가 이기는 중"); + return; + } + System.out.println("비기는 중"); + } + enum PieceAsset { BLACK_KING('K'), BLACK_QUEEN('Q'), From 07192b30c9a9505dbcf36e4db8cb478d52bd0467 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 12:08:51 +0900 Subject: [PATCH 14/45] =?UTF-8?q?fix:=20=EB=AA=85=EB=A0=B9=EC=96=B4=20?= =?UTF-8?q?=EC=98=88=EC=8B=9C=20=EC=B6=9C=EB=A0=A5=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/chess/view/OutputView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index f4194a0aadb..b7fb07c4c0a 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -12,7 +12,8 @@ public static void printGuide() { System.out.printf("> 체스 게임을 시작합니다.%n" + "> 게임 시작 : start%n" + "> 게임 종료 : end%n" - + "> 게임 이동 : move source위치 target위치 - 예. move b2 b3%n"); + + "> 게임 이동 : move source위치 target위치 - 예. move b2 b3%n" + + "> 현재 점수 확인 : status%n"); } public static void printChessBoard(List pieceDTOS) { From 96b6e56fe8201609eb0497860dbc1a53297b49cd Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 17:45:55 +0900 Subject: [PATCH 15/45] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Application.java | 6 ++--- .../chess/domain/board/ChessBoardWrapper.java | 27 ------------------- .../domain/{board => game}/ChessBoard.java | 4 +-- .../java/chess/domain/game/ChessGame.java | 12 ++++----- .../domain/{board => game}/InitialPieces.java | 2 +- .../{board => game}/PointCalculator.java | 2 +- .../domain/game/{ => command}/Command.java | 2 +- .../domain/game/{ => command}/EndCommand.java | 2 +- .../game/{ => command}/MoveCommand.java | 2 +- .../game/{ => command}/StartCommand.java | 2 +- .../game/{ => command}/StatusCommand.java | 2 +- .../piece/AbstractCatchOnMovePiece.java | 2 +- .../chess/domain/piece/AbstractPiece.java | 2 +- .../piece/AbstractStraightMovePiece.java | 2 +- src/main/java/chess/domain/piece/Bishop.java | 2 +- src/main/java/chess/domain/piece/King.java | 2 +- src/main/java/chess/domain/piece/Knight.java | 2 +- src/main/java/chess/domain/piece/Pawn.java | 2 +- src/main/java/chess/domain/piece/Piece.java | 2 +- src/main/java/chess/domain/piece/Queen.java | 2 +- src/main/java/chess/domain/piece/Rook.java | 2 +- src/main/java/chess/view/InputView.java | 10 +++---- .../{board => game}/ChessBoardTest.java | 2 +- .../chess/domain/game/EndCommandTest.java | 2 +- .../chess/domain/game/MoveCommandTest.java | 1 + .../chess/domain/game/StartCommandTest.java | 2 +- .../java/chess/domain/piece/BishopTest.java | 2 +- .../java/chess/domain/piece/KingTest.java | 2 +- .../java/chess/domain/piece/KnightTest.java | 2 +- .../java/chess/domain/piece/PawnTest.java | 2 +- .../java/chess/domain/piece/QueenTest.java | 2 +- .../java/chess/domain/piece/RookTest.java | 2 +- 32 files changed, 42 insertions(+), 70 deletions(-) delete mode 100644 src/main/java/chess/domain/board/ChessBoardWrapper.java rename src/main/java/chess/domain/{board => game}/ChessBoard.java (97%) rename src/main/java/chess/domain/{board => game}/InitialPieces.java (98%) rename src/main/java/chess/domain/{board => game}/PointCalculator.java (98%) rename src/main/java/chess/domain/game/{ => command}/Command.java (86%) rename src/main/java/chess/domain/game/{ => command}/EndCommand.java (91%) rename src/main/java/chess/domain/game/{ => command}/MoveCommand.java (92%) rename src/main/java/chess/domain/game/{ => command}/StartCommand.java (91%) rename src/main/java/chess/domain/game/{ => command}/StatusCommand.java (91%) rename src/test/java/chess/domain/{board => game}/ChessBoardTest.java (99%) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 317d1416497..61cd753e687 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -1,11 +1,11 @@ package chess; -import static chess.domain.game.EndCommand.END_COMMAND; +import static chess.domain.game.command.EndCommand.END_COMMAND; import chess.domain.Position; import chess.domain.game.ChessGame; -import chess.domain.game.Command; -import chess.domain.game.StatusCommand; +import chess.domain.game.command.Command; +import chess.domain.game.command.StatusCommand; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; diff --git a/src/main/java/chess/domain/board/ChessBoardWrapper.java b/src/main/java/chess/domain/board/ChessBoardWrapper.java deleted file mode 100644 index fa3442aeecd..00000000000 --- a/src/main/java/chess/domain/board/ChessBoardWrapper.java +++ /dev/null @@ -1,27 +0,0 @@ -package chess.domain.board; - -import chess.domain.Position; -import chess.domain.piece.Piece; -import chess.domain.piece.PieceMoveResult; -import chess.domain.piece.Team; -import java.util.List; - -public class ChessBoardWrapper { - private final ChessBoard chessBoard; - - public ChessBoardWrapper(ChessBoard chessBoard) { - this.chessBoard = chessBoard; - } - - public PieceMoveResult move(Position from, Position to) { - return chessBoard.move(from, to); - } - - public List getPiecesOnBoard() { - return chessBoard.getPiecesOnBoard(); - } - - public double calculatePoint(Team team) { - return chessBoard.calculatePoint(team); - } -} diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/game/ChessBoard.java similarity index 97% rename from src/main/java/chess/domain/board/ChessBoard.java rename to src/main/java/chess/domain/game/ChessBoard.java index 9dc3f868db2..4f761424978 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/game/ChessBoard.java @@ -1,6 +1,6 @@ -package chess.domain.board; +package chess.domain.game; -import static chess.domain.board.InitialPieces.INITIAL_PIECES; +import static chess.domain.game.InitialPieces.INITIAL_PIECES; import chess.domain.Position; import chess.domain.piece.Piece; diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 2ee933bb3ad..7d93c63f0db 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -1,29 +1,27 @@ package chess.domain.game; import chess.domain.Position; -import chess.domain.board.ChessBoard; -import chess.domain.board.ChessBoardWrapper; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; public class ChessGame { - private final ChessBoardWrapper chessBoardWrapper; + private final ChessBoard chessBoard; public ChessGame() { - this.chessBoardWrapper = new ChessBoardWrapper(new ChessBoard()); + this.chessBoard = new ChessBoard(); } public PieceMoveResult move(Position from, Position to) { - return chessBoardWrapper.move(from, to); + return chessBoard.move(from, to); } public double calculatePoint(Team team) { - return chessBoardWrapper.calculatePoint(team); + return chessBoard.calculatePoint(team); } public List getPiecesOnBoard() { - return chessBoardWrapper.getPiecesOnBoard(); + return chessBoard.getPiecesOnBoard(); } } diff --git a/src/main/java/chess/domain/board/InitialPieces.java b/src/main/java/chess/domain/game/InitialPieces.java similarity index 98% rename from src/main/java/chess/domain/board/InitialPieces.java rename to src/main/java/chess/domain/game/InitialPieces.java index 64f8eadbab3..6a7f46a1d12 100644 --- a/src/main/java/chess/domain/board/InitialPieces.java +++ b/src/main/java/chess/domain/game/InitialPieces.java @@ -1,4 +1,4 @@ -package chess.domain.board; +package chess.domain.game; import static chess.domain.Position.A1; import static chess.domain.Position.A2; diff --git a/src/main/java/chess/domain/board/PointCalculator.java b/src/main/java/chess/domain/game/PointCalculator.java similarity index 98% rename from src/main/java/chess/domain/board/PointCalculator.java rename to src/main/java/chess/domain/game/PointCalculator.java index ce51cbaeda6..c9e3ac3216b 100644 --- a/src/main/java/chess/domain/board/PointCalculator.java +++ b/src/main/java/chess/domain/game/PointCalculator.java @@ -1,4 +1,4 @@ -package chess.domain.board; +package chess.domain.game; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; diff --git a/src/main/java/chess/domain/game/Command.java b/src/main/java/chess/domain/game/command/Command.java similarity index 86% rename from src/main/java/chess/domain/game/Command.java rename to src/main/java/chess/domain/game/command/Command.java index 4496d31d256..aec10e6e0aa 100644 --- a/src/main/java/chess/domain/game/Command.java +++ b/src/main/java/chess/domain/game/command/Command.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.game.command; import java.util.List; diff --git a/src/main/java/chess/domain/game/EndCommand.java b/src/main/java/chess/domain/game/command/EndCommand.java similarity index 91% rename from src/main/java/chess/domain/game/EndCommand.java rename to src/main/java/chess/domain/game/command/EndCommand.java index d9935e49852..a4d4dc46d86 100644 --- a/src/main/java/chess/domain/game/EndCommand.java +++ b/src/main/java/chess/domain/game/command/EndCommand.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.game.command; import java.util.List; diff --git a/src/main/java/chess/domain/game/MoveCommand.java b/src/main/java/chess/domain/game/command/MoveCommand.java similarity index 92% rename from src/main/java/chess/domain/game/MoveCommand.java rename to src/main/java/chess/domain/game/command/MoveCommand.java index 58f8216507d..87749c15c03 100644 --- a/src/main/java/chess/domain/game/MoveCommand.java +++ b/src/main/java/chess/domain/game/command/MoveCommand.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.game.command; import chess.domain.Position; import java.util.Arrays; diff --git a/src/main/java/chess/domain/game/StartCommand.java b/src/main/java/chess/domain/game/command/StartCommand.java similarity index 91% rename from src/main/java/chess/domain/game/StartCommand.java rename to src/main/java/chess/domain/game/command/StartCommand.java index 5bee41f3299..8671a7427fa 100644 --- a/src/main/java/chess/domain/game/StartCommand.java +++ b/src/main/java/chess/domain/game/command/StartCommand.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.game.command; import java.util.List; diff --git a/src/main/java/chess/domain/game/StatusCommand.java b/src/main/java/chess/domain/game/command/StatusCommand.java similarity index 91% rename from src/main/java/chess/domain/game/StatusCommand.java rename to src/main/java/chess/domain/game/command/StatusCommand.java index 3c01a4d9de1..257cb39181f 100644 --- a/src/main/java/chess/domain/game/StatusCommand.java +++ b/src/main/java/chess/domain/game/command/StatusCommand.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.game.command; import java.util.List; diff --git a/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java b/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java index 2d2c6e1d6a4..bce1957a41c 100644 --- a/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java +++ b/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java @@ -5,7 +5,7 @@ import static chess.domain.piece.PieceMoveResult.SUCCESS; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Optional; abstract class AbstractCatchOnMovePiece extends AbstractPiece { diff --git a/src/main/java/chess/domain/piece/AbstractPiece.java b/src/main/java/chess/domain/piece/AbstractPiece.java index c3efb7511c6..770508f3946 100644 --- a/src/main/java/chess/domain/piece/AbstractPiece.java +++ b/src/main/java/chess/domain/piece/AbstractPiece.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; abstract class AbstractPiece implements Piece { private final Team team; diff --git a/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java b/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java index 54a87226a18..b2ba9c86d07 100644 --- a/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java +++ b/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java @@ -2,7 +2,7 @@ import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.List; import java.util.Optional; diff --git a/src/main/java/chess/domain/piece/Bishop.java b/src/main/java/chess/domain/piece/Bishop.java index 16ba67ebe26..fb155daca2a 100644 --- a/src/main/java/chess/domain/piece/Bishop.java +++ b/src/main/java/chess/domain/piece/Bishop.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Optional; public final class Bishop extends AbstractStraightMovePiece { diff --git a/src/main/java/chess/domain/piece/King.java b/src/main/java/chess/domain/piece/King.java index dba4ecff778..ed678d6a17e 100644 --- a/src/main/java/chess/domain/piece/King.java +++ b/src/main/java/chess/domain/piece/King.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Optional; public final class King extends AbstractCatchOnMovePiece { diff --git a/src/main/java/chess/domain/piece/Knight.java b/src/main/java/chess/domain/piece/Knight.java index 8816c91c966..2d5d9da2070 100644 --- a/src/main/java/chess/domain/piece/Knight.java +++ b/src/main/java/chess/domain/piece/Knight.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Optional; public final class Knight extends AbstractCatchOnMovePiece { diff --git a/src/main/java/chess/domain/piece/Pawn.java b/src/main/java/chess/domain/piece/Pawn.java index 120db8a6040..f109afa5b69 100644 --- a/src/main/java/chess/domain/piece/Pawn.java +++ b/src/main/java/chess/domain/piece/Pawn.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.List; import java.util.Optional; diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index 4182e5d4bc3..b5cb53138e1 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; public interface Piece { PieceMoveResult move(Position targetPosition, ChessBoard chessBoard); diff --git a/src/main/java/chess/domain/piece/Queen.java b/src/main/java/chess/domain/piece/Queen.java index 100aaf3c219..3094e7515f9 100644 --- a/src/main/java/chess/domain/piece/Queen.java +++ b/src/main/java/chess/domain/piece/Queen.java @@ -4,7 +4,7 @@ import static chess.domain.piece.PieceType.QUEEN; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Optional; public final class Queen extends AbstractStraightMovePiece { diff --git a/src/main/java/chess/domain/piece/Rook.java b/src/main/java/chess/domain/piece/Rook.java index 2b09226f107..801b5f940fa 100644 --- a/src/main/java/chess/domain/piece/Rook.java +++ b/src/main/java/chess/domain/piece/Rook.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Optional; public final class Rook extends AbstractStraightMovePiece { diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java index 82d5b0165a5..e36e9d53a97 100644 --- a/src/main/java/chess/view/InputView.java +++ b/src/main/java/chess/view/InputView.java @@ -1,10 +1,10 @@ package chess.view; -import chess.domain.game.Command; -import chess.domain.game.EndCommand; -import chess.domain.game.MoveCommand; -import chess.domain.game.StartCommand; -import chess.domain.game.StatusCommand; +import chess.domain.game.command.Command; +import chess.domain.game.command.EndCommand; +import chess.domain.game.command.MoveCommand; +import chess.domain.game.command.StartCommand; +import chess.domain.game.command.StatusCommand; import java.util.Scanner; public class InputView { diff --git a/src/test/java/chess/domain/board/ChessBoardTest.java b/src/test/java/chess/domain/game/ChessBoardTest.java similarity index 99% rename from src/test/java/chess/domain/board/ChessBoardTest.java rename to src/test/java/chess/domain/game/ChessBoardTest.java index 1854abfb7b4..2956820b26b 100644 --- a/src/test/java/chess/domain/board/ChessBoardTest.java +++ b/src/test/java/chess/domain/game/ChessBoardTest.java @@ -1,4 +1,4 @@ -package chess.domain.board; +package chess.domain.game; import static chess.domain.Position.A1; import static chess.domain.Position.A2; diff --git a/src/test/java/chess/domain/game/EndCommandTest.java b/src/test/java/chess/domain/game/EndCommandTest.java index 5c5737e0353..5fba07b874a 100644 --- a/src/test/java/chess/domain/game/EndCommandTest.java +++ b/src/test/java/chess/domain/game/EndCommandTest.java @@ -1,6 +1,6 @@ package chess.domain.game; -import static chess.domain.game.EndCommand.END_COMMAND; +import static chess.domain.game.command.EndCommand.END_COMMAND; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/chess/domain/game/MoveCommandTest.java b/src/test/java/chess/domain/game/MoveCommandTest.java index d910ff16d2d..39db70c6cc6 100644 --- a/src/test/java/chess/domain/game/MoveCommandTest.java +++ b/src/test/java/chess/domain/game/MoveCommandTest.java @@ -4,6 +4,7 @@ import static chess.domain.Position.A2; import chess.domain.Position; +import chess.domain.game.command.MoveCommand; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/chess/domain/game/StartCommandTest.java b/src/test/java/chess/domain/game/StartCommandTest.java index ee581d0f161..455eb8b1774 100644 --- a/src/test/java/chess/domain/game/StartCommandTest.java +++ b/src/test/java/chess/domain/game/StartCommandTest.java @@ -1,6 +1,6 @@ package chess.domain.game; -import static chess.domain.game.StartCommand.START_COMMAND; +import static chess.domain.game.command.StartCommand.START_COMMAND; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/chess/domain/piece/BishopTest.java b/src/test/java/chess/domain/piece/BishopTest.java index 1bb02365e6a..ab98fcbde6c 100644 --- a/src/test/java/chess/domain/piece/BishopTest.java +++ b/src/test/java/chess/domain/piece/BishopTest.java @@ -21,7 +21,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/KingTest.java b/src/test/java/chess/domain/piece/KingTest.java index 9c78a785ad9..ebc35cf0569 100644 --- a/src/test/java/chess/domain/piece/KingTest.java +++ b/src/test/java/chess/domain/piece/KingTest.java @@ -16,7 +16,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/KnightTest.java b/src/test/java/chess/domain/piece/KnightTest.java index b47c389dab3..f54acf54333 100644 --- a/src/test/java/chess/domain/piece/KnightTest.java +++ b/src/test/java/chess/domain/piece/KnightTest.java @@ -16,7 +16,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/PawnTest.java b/src/test/java/chess/domain/piece/PawnTest.java index 59ce964f2ec..d0b749e1704 100644 --- a/src/test/java/chess/domain/piece/PawnTest.java +++ b/src/test/java/chess/domain/piece/PawnTest.java @@ -19,7 +19,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.List; import java.util.stream.Stream; import org.assertj.core.api.Assertions; diff --git a/src/test/java/chess/domain/piece/QueenTest.java b/src/test/java/chess/domain/piece/QueenTest.java index 6f9d37a9916..689224c4e26 100644 --- a/src/test/java/chess/domain/piece/QueenTest.java +++ b/src/test/java/chess/domain/piece/QueenTest.java @@ -35,7 +35,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/RookTest.java b/src/test/java/chess/domain/piece/RookTest.java index 3e908a6e5dc..d070d7c7840 100644 --- a/src/test/java/chess/domain/piece/RookTest.java +++ b/src/test/java/chess/domain/piece/RookTest.java @@ -22,7 +22,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.board.ChessBoard; +import chess.domain.game.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; From f7f9d51cb32d0b0d91984bd1d650db093759f735 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 22:19:52 +0900 Subject: [PATCH 16/45] =?UTF-8?q?refactor:=20ChessBoard=20=EC=99=80=20Ches?= =?UTF-8?q?sGame=20=EC=82=AC=EC=9D=B4=EC=97=90=20=EC=96=B4=EB=8E=81?= =?UTF-8?q?=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Application.java | 7 ++-- .../domain/{game => board}/ChessBoard.java | 5 +-- .../chess/domain/board/ChessBoardAdaptor.java | 35 +++++++++++++++++++ .../domain/{game => board}/InitialPieces.java | 2 +- .../domain/game/ChessBoardForChessGame.java | 15 ++++++++ .../java/chess/domain/game/ChessGame.java | 14 ++++---- .../chess/domain/game/PointCalculator.java | 4 +-- .../piece/AbstractCatchOnMovePiece.java | 2 +- .../chess/domain/piece/AbstractPiece.java | 2 +- .../piece/AbstractStraightMovePiece.java | 2 +- src/main/java/chess/domain/piece/Bishop.java | 2 +- src/main/java/chess/domain/piece/King.java | 2 +- src/main/java/chess/domain/piece/Knight.java | 2 +- src/main/java/chess/domain/piece/Pawn.java | 2 +- src/main/java/chess/domain/piece/Piece.java | 2 +- src/main/java/chess/domain/piece/Queen.java | 2 +- src/main/java/chess/domain/piece/Rook.java | 2 +- .../{game => board}/ChessBoardTest.java | 2 +- .../java/chess/domain/piece/BishopTest.java | 2 +- .../java/chess/domain/piece/KingTest.java | 2 +- .../java/chess/domain/piece/KnightTest.java | 2 +- .../java/chess/domain/piece/PawnTest.java | 2 +- .../java/chess/domain/piece/QueenTest.java | 2 +- .../java/chess/domain/piece/RookTest.java | 2 +- 24 files changed, 83 insertions(+), 33 deletions(-) rename src/main/java/chess/domain/{game => board}/ChessBoard.java (96%) create mode 100644 src/main/java/chess/domain/board/ChessBoardAdaptor.java rename src/main/java/chess/domain/{game => board}/InitialPieces.java (98%) create mode 100644 src/main/java/chess/domain/game/ChessBoardForChessGame.java rename src/test/java/chess/domain/{game => board}/ChessBoardTest.java (99%) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 61cd753e687..27230755e5a 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -2,9 +2,9 @@ import static chess.domain.game.command.EndCommand.END_COMMAND; -import chess.domain.Position; import chess.domain.game.ChessGame; import chess.domain.game.command.Command; +import chess.domain.game.command.MoveCommand; import chess.domain.game.command.StatusCommand; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; @@ -75,10 +75,7 @@ private static void printStatus(ChessGame chessGame) { } private static PieceMoveResult playGame(Command moveCommand, ChessGame chessGame) { - List options = moveCommand.getOptions(); - Position from = options.get(0); - Position to = options.get(1); - PieceMoveResult moveResult = chessGame.move(from, to); + PieceMoveResult moveResult = chessGame.move((MoveCommand) moveCommand); printPiecesOnChessBoard(chessGame); printReInputGuideIfNeed(moveResult); printWinnerIfNeed(moveResult); diff --git a/src/main/java/chess/domain/game/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java similarity index 96% rename from src/main/java/chess/domain/game/ChessBoard.java rename to src/main/java/chess/domain/board/ChessBoard.java index 4f761424978..8fd572becf2 100644 --- a/src/main/java/chess/domain/game/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -1,8 +1,9 @@ -package chess.domain.game; +package chess.domain.board; -import static chess.domain.game.InitialPieces.INITIAL_PIECES; +import static chess.domain.board.InitialPieces.INITIAL_PIECES; import chess.domain.Position; +import chess.domain.game.PointCalculator; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; diff --git a/src/main/java/chess/domain/board/ChessBoardAdaptor.java b/src/main/java/chess/domain/board/ChessBoardAdaptor.java new file mode 100644 index 00000000000..4c15da1e1e5 --- /dev/null +++ b/src/main/java/chess/domain/board/ChessBoardAdaptor.java @@ -0,0 +1,35 @@ +package chess.domain.board; + +import chess.domain.Position; +import chess.domain.game.ChessBoardForChessGame; +import chess.domain.game.command.MoveCommand; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceMoveResult; +import chess.domain.piece.Team; +import java.util.List; + +public class ChessBoardAdaptor implements ChessBoardForChessGame { + private final ChessBoard chessBoard; + + public ChessBoardAdaptor(ChessBoard chessBoard) { + this.chessBoard = chessBoard; + } + + @Override + public PieceMoveResult move(MoveCommand moveCommand) { + List positions = moveCommand.getOptions(); + Position from = positions.get(0); + Position to = positions.get(1); + return chessBoard.move(from, to); + } + + @Override + public List getPiecesOnBoard() { + return chessBoard.getPiecesOnBoard(); + } + + @Override + public double calculateTeamScore(Team team) { + return chessBoard.calculatePoint(team); + } +} diff --git a/src/main/java/chess/domain/game/InitialPieces.java b/src/main/java/chess/domain/board/InitialPieces.java similarity index 98% rename from src/main/java/chess/domain/game/InitialPieces.java rename to src/main/java/chess/domain/board/InitialPieces.java index 6a7f46a1d12..64f8eadbab3 100644 --- a/src/main/java/chess/domain/game/InitialPieces.java +++ b/src/main/java/chess/domain/board/InitialPieces.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.board; import static chess.domain.Position.A1; import static chess.domain.Position.A2; diff --git a/src/main/java/chess/domain/game/ChessBoardForChessGame.java b/src/main/java/chess/domain/game/ChessBoardForChessGame.java new file mode 100644 index 00000000000..cce9ba009b5 --- /dev/null +++ b/src/main/java/chess/domain/game/ChessBoardForChessGame.java @@ -0,0 +1,15 @@ +package chess.domain.game; + +import chess.domain.game.command.MoveCommand; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceMoveResult; +import chess.domain.piece.Team; +import java.util.List; + +public interface ChessBoardForChessGame { + PieceMoveResult move(MoveCommand moveCommand); + + List getPiecesOnBoard(); + + double calculateTeamScore(Team team); +} diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 7d93c63f0db..3d1cf593c34 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -1,24 +1,26 @@ package chess.domain.game; -import chess.domain.Position; +import chess.domain.board.ChessBoard; +import chess.domain.board.ChessBoardAdaptor; +import chess.domain.game.command.MoveCommand; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; public class ChessGame { - private final ChessBoard chessBoard; + private final ChessBoardForChessGame chessBoard; public ChessGame() { - this.chessBoard = new ChessBoard(); + this.chessBoard = new ChessBoardAdaptor(new ChessBoard()); } - public PieceMoveResult move(Position from, Position to) { - return chessBoard.move(from, to); + public PieceMoveResult move(MoveCommand moveCommand) { + return chessBoard.move(moveCommand); } public double calculatePoint(Team team) { - return chessBoard.calculatePoint(team); + return chessBoard.calculateTeamScore(team); } public List getPiecesOnBoard() { diff --git a/src/main/java/chess/domain/game/PointCalculator.java b/src/main/java/chess/domain/game/PointCalculator.java index c9e3ac3216b..0f65f939ed9 100644 --- a/src/main/java/chess/domain/game/PointCalculator.java +++ b/src/main/java/chess/domain/game/PointCalculator.java @@ -8,8 +8,8 @@ import java.util.Map; import java.util.stream.Collectors; -class PointCalculator { - static double calculatePoint(Team team, List piecesOnBoard) { +public class PointCalculator { + public static double calculatePoint(Team team, List piecesOnBoard) { piecesOnBoard = Collections.unmodifiableList(piecesOnBoard); double totalPoint = calculateWithOutSameColumnPawn(team, piecesOnBoard); Map> pawnsAtSameColumn = pawnGroupingByColumn(team, piecesOnBoard); diff --git a/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java b/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java index bce1957a41c..2d2c6e1d6a4 100644 --- a/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java +++ b/src/main/java/chess/domain/piece/AbstractCatchOnMovePiece.java @@ -5,7 +5,7 @@ import static chess.domain.piece.PieceMoveResult.SUCCESS; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Optional; abstract class AbstractCatchOnMovePiece extends AbstractPiece { diff --git a/src/main/java/chess/domain/piece/AbstractPiece.java b/src/main/java/chess/domain/piece/AbstractPiece.java index 770508f3946..c3efb7511c6 100644 --- a/src/main/java/chess/domain/piece/AbstractPiece.java +++ b/src/main/java/chess/domain/piece/AbstractPiece.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; abstract class AbstractPiece implements Piece { private final Team team; diff --git a/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java b/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java index b2ba9c86d07..54a87226a18 100644 --- a/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java +++ b/src/main/java/chess/domain/piece/AbstractStraightMovePiece.java @@ -2,7 +2,7 @@ import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.List; import java.util.Optional; diff --git a/src/main/java/chess/domain/piece/Bishop.java b/src/main/java/chess/domain/piece/Bishop.java index fb155daca2a..16ba67ebe26 100644 --- a/src/main/java/chess/domain/piece/Bishop.java +++ b/src/main/java/chess/domain/piece/Bishop.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Optional; public final class Bishop extends AbstractStraightMovePiece { diff --git a/src/main/java/chess/domain/piece/King.java b/src/main/java/chess/domain/piece/King.java index ed678d6a17e..dba4ecff778 100644 --- a/src/main/java/chess/domain/piece/King.java +++ b/src/main/java/chess/domain/piece/King.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Optional; public final class King extends AbstractCatchOnMovePiece { diff --git a/src/main/java/chess/domain/piece/Knight.java b/src/main/java/chess/domain/piece/Knight.java index 2d5d9da2070..8816c91c966 100644 --- a/src/main/java/chess/domain/piece/Knight.java +++ b/src/main/java/chess/domain/piece/Knight.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Optional; public final class Knight extends AbstractCatchOnMovePiece { diff --git a/src/main/java/chess/domain/piece/Pawn.java b/src/main/java/chess/domain/piece/Pawn.java index f109afa5b69..120db8a6040 100644 --- a/src/main/java/chess/domain/piece/Pawn.java +++ b/src/main/java/chess/domain/piece/Pawn.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.List; import java.util.Optional; diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index b5cb53138e1..4182e5d4bc3 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; public interface Piece { PieceMoveResult move(Position targetPosition, ChessBoard chessBoard); diff --git a/src/main/java/chess/domain/piece/Queen.java b/src/main/java/chess/domain/piece/Queen.java index 3094e7515f9..100aaf3c219 100644 --- a/src/main/java/chess/domain/piece/Queen.java +++ b/src/main/java/chess/domain/piece/Queen.java @@ -4,7 +4,7 @@ import static chess.domain.piece.PieceType.QUEEN; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Optional; public final class Queen extends AbstractStraightMovePiece { diff --git a/src/main/java/chess/domain/piece/Rook.java b/src/main/java/chess/domain/piece/Rook.java index 801b5f940fa..2b09226f107 100644 --- a/src/main/java/chess/domain/piece/Rook.java +++ b/src/main/java/chess/domain/piece/Rook.java @@ -1,7 +1,7 @@ package chess.domain.piece; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Optional; public final class Rook extends AbstractStraightMovePiece { diff --git a/src/test/java/chess/domain/game/ChessBoardTest.java b/src/test/java/chess/domain/board/ChessBoardTest.java similarity index 99% rename from src/test/java/chess/domain/game/ChessBoardTest.java rename to src/test/java/chess/domain/board/ChessBoardTest.java index 2956820b26b..1854abfb7b4 100644 --- a/src/test/java/chess/domain/game/ChessBoardTest.java +++ b/src/test/java/chess/domain/board/ChessBoardTest.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.board; import static chess.domain.Position.A1; import static chess.domain.Position.A2; diff --git a/src/test/java/chess/domain/piece/BishopTest.java b/src/test/java/chess/domain/piece/BishopTest.java index ab98fcbde6c..1bb02365e6a 100644 --- a/src/test/java/chess/domain/piece/BishopTest.java +++ b/src/test/java/chess/domain/piece/BishopTest.java @@ -21,7 +21,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/KingTest.java b/src/test/java/chess/domain/piece/KingTest.java index ebc35cf0569..9c78a785ad9 100644 --- a/src/test/java/chess/domain/piece/KingTest.java +++ b/src/test/java/chess/domain/piece/KingTest.java @@ -16,7 +16,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/KnightTest.java b/src/test/java/chess/domain/piece/KnightTest.java index f54acf54333..b47c389dab3 100644 --- a/src/test/java/chess/domain/piece/KnightTest.java +++ b/src/test/java/chess/domain/piece/KnightTest.java @@ -16,7 +16,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/PawnTest.java b/src/test/java/chess/domain/piece/PawnTest.java index d0b749e1704..59ce964f2ec 100644 --- a/src/test/java/chess/domain/piece/PawnTest.java +++ b/src/test/java/chess/domain/piece/PawnTest.java @@ -19,7 +19,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.List; import java.util.stream.Stream; import org.assertj.core.api.Assertions; diff --git a/src/test/java/chess/domain/piece/QueenTest.java b/src/test/java/chess/domain/piece/QueenTest.java index 689224c4e26..6f9d37a9916 100644 --- a/src/test/java/chess/domain/piece/QueenTest.java +++ b/src/test/java/chess/domain/piece/QueenTest.java @@ -35,7 +35,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; diff --git a/src/test/java/chess/domain/piece/RookTest.java b/src/test/java/chess/domain/piece/RookTest.java index d070d7c7840..3e908a6e5dc 100644 --- a/src/test/java/chess/domain/piece/RookTest.java +++ b/src/test/java/chess/domain/piece/RookTest.java @@ -22,7 +22,7 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.ChessBoard; +import chess.domain.board.ChessBoard; import java.util.Arrays; import java.util.List; import java.util.Set; From 9e2e7a802bebef01b3aebce5ad7fc95012ad5b5b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 26 Mar 2024 22:37:18 +0900 Subject: [PATCH 17/45] =?UTF-8?q?refactor:=20ChessGame=EC=9D=B4=20?= =?UTF-8?q?=ED=95=9C=EB=B2=88=EC=97=90=20=EB=AA=A8=EB=93=A0=20=ED=8C=80?= =?UTF-8?q?=EC=9D=98=20=EC=A0=90=EC=88=98=EB=A5=BC=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Application.java | 17 ++++++++++------- .../chess/domain/board/ChessBoardAdaptor.java | 10 ++++++++-- .../domain/game/ChessBoardForChessGame.java | 3 ++- src/main/java/chess/domain/game/ChessGame.java | 5 +++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 27230755e5a..acc19192b84 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -1,6 +1,8 @@ package chess; import static chess.domain.game.command.EndCommand.END_COMMAND; +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; import chess.domain.game.ChessGame; import chess.domain.game.command.Command; @@ -14,6 +16,7 @@ import chess.view.InputView; import chess.view.OutputView; import java.util.List; +import java.util.Map; public class Application { public static void main(String[] args) { @@ -63,19 +66,19 @@ private static PieceMoveResult playGameOrPrintStatus(Command moveOrStatus, Chess printStatus(chessGame); return PieceMoveResult.FAILURE; } - return playGame(moveOrStatus, chessGame); + return playGame((MoveCommand) moveOrStatus, chessGame); } private static void printStatus(ChessGame chessGame) { - double whiteTeamPoint = chessGame.calculatePoint(Team.WHITE); - OutputView.printStatus(Team.WHITE, whiteTeamPoint); - double blackTeamPoint = chessGame.calculatePoint(Team.BLACK); - OutputView.printStatus(Team.BLACK, blackTeamPoint); + Map scoresGroupingByTeam = chessGame.calculateScores(); + scoresGroupingByTeam.forEach(OutputView::printStatus); + double whiteTeamPoint = scoresGroupingByTeam.get(WHITE); + double blackTeamPoint = scoresGroupingByTeam.get(BLACK); OutputView.currentWinner(whiteTeamPoint, blackTeamPoint); } - private static PieceMoveResult playGame(Command moveCommand, ChessGame chessGame) { - PieceMoveResult moveResult = chessGame.move((MoveCommand) moveCommand); + private static PieceMoveResult playGame(MoveCommand moveCommand, ChessGame chessGame) { + PieceMoveResult moveResult = chessGame.move(moveCommand); printPiecesOnChessBoard(chessGame); printReInputGuideIfNeed(moveResult); printWinnerIfNeed(moveResult); diff --git a/src/main/java/chess/domain/board/ChessBoardAdaptor.java b/src/main/java/chess/domain/board/ChessBoardAdaptor.java index 4c15da1e1e5..8a7146c0bea 100644 --- a/src/main/java/chess/domain/board/ChessBoardAdaptor.java +++ b/src/main/java/chess/domain/board/ChessBoardAdaptor.java @@ -1,5 +1,8 @@ package chess.domain.board; +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; + import chess.domain.Position; import chess.domain.game.ChessBoardForChessGame; import chess.domain.game.command.MoveCommand; @@ -7,6 +10,7 @@ import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; +import java.util.Map; public class ChessBoardAdaptor implements ChessBoardForChessGame { private final ChessBoard chessBoard; @@ -29,7 +33,9 @@ public List getPiecesOnBoard() { } @Override - public double calculateTeamScore(Team team) { - return chessBoard.calculatePoint(team); + public Map calculateScores() { + double blackTeamScore = chessBoard.calculatePoint(BLACK); + double whiteTeamScore = chessBoard.calculatePoint(WHITE); + return Map.of(BLACK, blackTeamScore, WHITE, whiteTeamScore); } } diff --git a/src/main/java/chess/domain/game/ChessBoardForChessGame.java b/src/main/java/chess/domain/game/ChessBoardForChessGame.java index cce9ba009b5..a865a233ef4 100644 --- a/src/main/java/chess/domain/game/ChessBoardForChessGame.java +++ b/src/main/java/chess/domain/game/ChessBoardForChessGame.java @@ -5,11 +5,12 @@ import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; +import java.util.Map; public interface ChessBoardForChessGame { PieceMoveResult move(MoveCommand moveCommand); List getPiecesOnBoard(); - double calculateTeamScore(Team team); + Map calculateScores(); } diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 3d1cf593c34..2d2bd25fc57 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -7,6 +7,7 @@ import chess.domain.piece.PieceMoveResult; import chess.domain.piece.Team; import java.util.List; +import java.util.Map; public class ChessGame { private final ChessBoardForChessGame chessBoard; @@ -19,8 +20,8 @@ public PieceMoveResult move(MoveCommand moveCommand) { return chessBoard.move(moveCommand); } - public double calculatePoint(Team team) { - return chessBoard.calculateTeamScore(team); + public Map calculateScores() { + return chessBoard.calculateScores(); } public List getPiecesOnBoard() { From de4004e4b2d28352d370ef45bffa2f26e7f156dc Mon Sep 17 00:00:00 2001 From: robinjoon Date: Wed, 27 Mar 2024 17:27:01 +0900 Subject: [PATCH 18/45] =?UTF-8?q?docs:=20=EC=A0=80=EC=9E=A5=ED=95=B4?= =?UTF-8?q?=EC=95=BC=20=ED=95=98=EB=8A=94=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EA=B0=80=20=EB=AC=B4=EC=97=87=EC=9D=B8=EC=A7=80=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 1c4fe9e057a..ac6698e275b 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,10 @@ - [x] 체스 판 출력 기능 - [x] 안내 문구 출력 기능 - [x] 점수 출력 기능 + +## 데이터베이스 + +### 저장해야 할 데이터 + +1. 각 기물의 위치 +2. 현재 기물을 움직일 수 있는 팀 From 20bccc8d48f789377fd4f59f4daa5cddca259ecc Mon Sep 17 00:00:00 2001 From: robinjoon Date: Thu, 28 Mar 2024 16:16:17 +0900 Subject: [PATCH 19/45] =?UTF-8?q?docs:=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index ac6698e275b..7903f590e86 100644 --- a/README.md +++ b/README.md @@ -85,3 +85,44 @@ 1. 각 기물의 위치 2. 현재 기물을 움직일 수 있는 팀 + +### 테이블 스키마 + +``` SQL +create table piece ( + piece_type varchar(16), + primary key(piece_type) +); + +create table position ( + `name` char(2), + primary key(`name`) +); + +create table team ( + team_name varchar(16), + primary key(team_name) +); + +CREATE TABLE `game` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `team_name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + PRIMARY KEY (`id`), + KEY `fj_team_game` (`team_name`), + CONSTRAINT `fj_team_game` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +CREATE TABLE `pieces_on_board` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `piece_type` varchar(16) NOT NULL, + `team_name` varchar(16) NOT NULL, + `name` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + PRIMARY KEY (`id`), + KEY `fk-piece-pieces_on_board` (`piece_type`), + KEY `fk-position-pieces_on_board` (`name`), + KEY `fk-team-pieces_on_board` (`team_name`), + CONSTRAINT `fk-piece-pieces_on_board` FOREIGN KEY (`piece_type`) REFERENCES `piece` (`piece_type`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `fk-position-pieces_on_board` FOREIGN KEY (`name`) REFERENCES `position` (`name`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `fk-team-pieces_on_board` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +``` From 7bf1c6915b5e3fe88333ff7a5d56a4ca1633f2e1 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Thu, 28 Mar 2024 18:09:25 +0900 Subject: [PATCH 20/45] =?UTF-8?q?docs:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7903f590e86..9627298eda0 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ - [x] 체스 판 출력 기능 - [x] 안내 문구 출력 기능 - [x] 점수 출력 기능 +- [ ] 데이터 베이스에 저장하는 기능 + - [ ] 기물을 저장하는 기능 ## 데이터베이스 @@ -106,23 +108,23 @@ create table team ( CREATE TABLE `game` ( `id` int unsigned NOT NULL AUTO_INCREMENT, - `team_name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `current_team_name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, PRIMARY KEY (`id`), - KEY `fj_team_game` (`team_name`), - CONSTRAINT `fj_team_game` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT + KEY `fj_team_game` (`current_team_name`), + CONSTRAINT `fj_team_game` FOREIGN KEY (`current_team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE TABLE `pieces_on_board` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `piece_type` varchar(16) NOT NULL, `team_name` varchar(16) NOT NULL, - `name` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `position_name` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, PRIMARY KEY (`id`), KEY `fk-piece-pieces_on_board` (`piece_type`), - KEY `fk-position-pieces_on_board` (`name`), + KEY `fk-position-pieces_on_board` (`position_name`), KEY `fk-team-pieces_on_board` (`team_name`), CONSTRAINT `fk-piece-pieces_on_board` FOREIGN KEY (`piece_type`) REFERENCES `piece` (`piece_type`) ON DELETE RESTRICT ON UPDATE RESTRICT, - CONSTRAINT `fk-position-pieces_on_board` FOREIGN KEY (`name`) REFERENCES `position` (`name`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `fk-position-pieces_on_board` FOREIGN KEY (`position_name`) REFERENCES `position` (`name`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `fk-team-pieces_on_board` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ``` From f4977629dc737306c07f5c81ac33185ef428ce14 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Thu, 28 Mar 2024 20:21:35 +0900 Subject: [PATCH 21/45] =?UTF-8?q?feat:=20=EA=B8=B0=EB=AC=BC=EC=9D=84=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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 --- README.md | 2 +- build.gradle | 1 + .../java/chess/dao/DBConnectionCache.java | 44 +++++++ .../java/chess/dao/PiecesOnChessBoardDAO.java | 17 +++ .../dao/PiecesOnChessBoardDAOForMysql.java | 122 ++++++++++++++++++ src/main/java/chess/domain/Position.java | 2 +- .../chess/domain/piece/AbstractPiece.java | 24 ++++ src/main/java/chess/domain/piece/Pawn.java | 24 ++++ .../PiecesOnChessBoardDAOForMysqlTest.java | 90 +++++++++++++ 9 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 src/main/java/chess/dao/DBConnectionCache.java create mode 100644 src/main/java/chess/dao/PiecesOnChessBoardDAO.java create mode 100644 src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java create mode 100644 src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java diff --git a/README.md b/README.md index 9627298eda0..fe733a6c622 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ - [x] 안내 문구 출력 기능 - [x] 점수 출력 기능 - [ ] 데이터 베이스에 저장하는 기능 - - [ ] 기물을 저장하는 기능 + - [x] 기물을 저장하는 기능 ## 데이터베이스 diff --git a/build.gradle b/build.gradle index 3697236c6fb..8c605072e94 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,7 @@ dependencies { testImplementation platform('org.assertj:assertj-bom:3.25.1') testImplementation('org.junit.jupiter:junit-jupiter') testImplementation('org.assertj:assertj-core') + runtimeOnly("com.mysql:mysql-connector-j:8.3.0") } java { diff --git a/src/main/java/chess/dao/DBConnectionCache.java b/src/main/java/chess/dao/DBConnectionCache.java new file mode 100644 index 00000000000..0f8b838bb1a --- /dev/null +++ b/src/main/java/chess/dao/DBConnectionCache.java @@ -0,0 +1,44 @@ +package chess.dao; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class DBConnectionCache { + private final DBConnectionParameters dbConnectionParameters; + private Connection connection; + + public DBConnectionCache(String url, String userName, String password) { + dbConnectionParameters = new DBConnectionParameters(url, userName, password); + connection = createConnection(dbConnectionParameters); + } + + private Connection createConnection(DBConnectionParameters dbConnectionParameters) { + String url = dbConnectionParameters.url; + String userName = dbConnectionParameters.userName; + String password = dbConnectionParameters.password; + try { + return DriverManager.getConnection(url, userName, password); + } catch (SQLException e) { + throw new RuntimeException("DB 접속 에러", e); + } + } + + public Connection getConnection() { + try { + return getConnectionCanThrow(); + } catch (SQLException e) { + throw new RuntimeException("DB 접속 에러"); + } + } + + private Connection getConnectionCanThrow() throws SQLException { + if (!connection.isValid(1)) { + connection = createConnection(dbConnectionParameters); + } + return connection; + } + + private record DBConnectionParameters(String url, String userName, String password) { + } +} diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java new file mode 100644 index 00000000000..ecd240f8ffe --- /dev/null +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java @@ -0,0 +1,17 @@ +package chess.dao; + +import chess.domain.Position; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.domain.piece.Team; +import java.util.List; + +public interface PiecesOnChessBoardDAO { + List selectAll(); + + boolean delete(Position targetPosition); + + boolean save(Piece piece); + + boolean update(Position targetPosition, PieceType pieceType, Team team); +} diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java new file mode 100644 index 00000000000..bab8732e30f --- /dev/null +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java @@ -0,0 +1,122 @@ +package chess.dao; + +import chess.domain.Position; +import chess.domain.piece.Bishop; +import chess.domain.piece.King; +import chess.domain.piece.Knight; +import chess.domain.piece.Pawn; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.domain.piece.Queen; +import chess.domain.piece.Rook; +import chess.domain.piece.Team; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class PiecesOnChessBoardDAOForMysql implements PiecesOnChessBoardDAO { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + private final DBConnectionCache dbConnectionCache; + + public PiecesOnChessBoardDAOForMysql() { + this(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); + } + + public PiecesOnChessBoardDAOForMysql(String dbUrl, String userName, String password) { + this.dbConnectionCache = new DBConnectionCache(dbUrl, userName, password); + } + + @Override + public List selectAll() { + Connection connection = dbConnectionCache.getConnection(); + try { + PreparedStatement preparedStatement = connection.prepareStatement( + "select piece_type, team_name, position_name from pieces_on_board"); + ResultSet resultSet = preparedStatement.executeQuery(); + List selected = parsingResultSet(resultSet); + return selected; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private List parsingResultSet(ResultSet resultSet) throws SQLException { + List selected = new ArrayList<>(); + while (resultSet.next()) { + String piece_type = resultSet.getString(1); + String team_name = resultSet.getString(2); + String position_name = resultSet.getString(3); + PieceType pieceType = PieceType.valueOf(piece_type); + Team team = Team.valueOf(team_name); + Position position = Position.valueOf(position_name); + Piece piece = mapToPiece(pieceType, team, position); + selected.add(piece); + } + return Collections.unmodifiableList(selected); + } + + private Piece mapToPiece(PieceType pieceType, Team team, Position position) { + return switch (pieceType) { + case BISHOP -> new Bishop(position, team); + case KING -> new King(position, team); + case KNIGHT -> new Knight(position, team); + case PAWN -> new Pawn(position, team); + case QUEEN -> new Queen(position, team); + case ROOK -> new Rook(position, team); + }; + } + + @Override + public boolean delete(Position targetPosition) { + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement( + "delete from pieces_on_board where position_name = ?"); + preparedStatement.setString(1, targetPosition.name()); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean save(Piece piece) { + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement( + "insert into pieces_on_board (piece_type, team_name, position_name) values ( ?, ? ,? )"); + PieceType pieceType = piece.getPieceType(); + Team team = piece.getTeam(); + int row = piece.getRow(); + int column = piece.getColumn(); + Position position = Position.getInstance(row, column); + preparedStatement.setString(1, pieceType.name()); + preparedStatement.setString(2, team.name()); + preparedStatement.setString(3, position.name()); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean update(Position targetPosition, PieceType pieceType, Team team) { + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement( + "update pieces_on_board set piece_type = ?, team_name = ? where position_name = ?"); + preparedStatement.setString(1, pieceType.name()); + preparedStatement.setString(2, team.name()); + preparedStatement.setString(3, targetPosition.name()); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/chess/domain/Position.java b/src/main/java/chess/domain/Position.java index 1fa07cd4bf6..513d4014f5a 100644 --- a/src/main/java/chess/domain/Position.java +++ b/src/main/java/chess/domain/Position.java @@ -24,7 +24,7 @@ public enum Position { this.column = column; } - static Position getInstance(int row, int column) { + public static Position getInstance(int row, int column) { return Arrays.stream(values()) .filter(position -> position.row == row) .filter(position -> position.column == column) diff --git a/src/main/java/chess/domain/piece/AbstractPiece.java b/src/main/java/chess/domain/piece/AbstractPiece.java index c3efb7511c6..59d61fc00fa 100644 --- a/src/main/java/chess/domain/piece/AbstractPiece.java +++ b/src/main/java/chess/domain/piece/AbstractPiece.java @@ -54,4 +54,28 @@ public boolean isTeamWith(Team team) { protected Position getPosition() { return position; } + + @Override + public int hashCode() { + int result = team != null ? team.hashCode() : 0; + result = 31 * result + (position != null ? position.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + AbstractPiece that = (AbstractPiece) o; + + if (team != that.team) { + return false; + } + return position == that.position; + } } diff --git a/src/main/java/chess/domain/piece/Pawn.java b/src/main/java/chess/domain/piece/Pawn.java index 120db8a6040..c4c9f927b24 100644 --- a/src/main/java/chess/domain/piece/Pawn.java +++ b/src/main/java/chess/domain/piece/Pawn.java @@ -80,6 +80,30 @@ private boolean isOtherTeam(Position targetPosition, ChessBoard chessBoard) { .isPresent(); } + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (initialPosition != null ? initialPosition.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + Pawn pawn = (Pawn) o; + + return initialPosition == pawn.initialPosition; + } + @Override public PieceType getPieceType() { return PieceType.PAWN; diff --git a/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java b/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java new file mode 100644 index 00000000000..0dca41c46d7 --- /dev/null +++ b/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java @@ -0,0 +1,90 @@ +package chess.dao; + +import static chess.domain.Position.A1; +import static chess.domain.Position.A2; +import static chess.domain.Position.A4; +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; + +import chess.domain.piece.Pawn; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PiecesOnChessBoardDAOForMysqlTest { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + + @BeforeEach + public void initDB() throws SQLException { + DBConnectionCache dbConnectionCache = new DBConnectionCache(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); + Connection connection = dbConnectionCache.getConnection(); + deleteAllData(connection); + insertInitialData(connection); + connection.close(); + } + + private static void deleteAllData(Connection connection) throws SQLException { + PreparedStatement preparedStatement = connection.prepareStatement("delete FROM pieces_on_board"); + preparedStatement.execute(); + } + + private static void insertInitialData(Connection connection) throws SQLException { + PreparedStatement preparedStatement; + preparedStatement = connection.prepareStatement( + "insert into pieces_on_board(piece_type, team_name, position_name) values ( ? ,? ,? ), (?, ?, ?)"); + preparedStatement.setString(1, "PAWN"); + preparedStatement.setString(2, "WHITE"); + preparedStatement.setString(3, "A1"); + preparedStatement.setString(4, "PAWN"); + preparedStatement.setString(5, "BLACK"); + preparedStatement.setString(6, "A2"); + preparedStatement.execute(); + } + + @Test + @DisplayName("데이터베이스에 저장되어있는 모든 기물이 제대로 조회되는지 검증") + void selectAll() { + PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); + List selected = dao.selectAll(); + Assertions.assertThat(selected) + .containsExactlyInAnyOrder(new Pawn(A1, WHITE), new Pawn(A2, BLACK)); + } + + @Test + @DisplayName("데이터베이스에서 특정 기물을 지울 수 있는지 검증") + void delete() { + PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); + + boolean deleteSuccess = dao.delete(A2); + Assertions.assertThat(deleteSuccess) + .isTrue(); + } + + @Test + @DisplayName("데이터베이스에서 특정 기물을 저장할 수 있는지 검증") + void save() { + PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); + + boolean saveSuccess = dao.save(new Pawn(A4, BLACK)); + Assertions.assertThat(saveSuccess) + .isTrue(); + } + + @Test + @DisplayName("특정 위치의 기물을 다른 것으로 변경할 수 있는지 검증") + void update() { + PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); + boolean success = dao.update(A2, PieceType.BISHOP, BLACK); + Assertions.assertThat(success) + .isTrue(); + } +} From 20f434b2d14d3283a760e1b26ba894472948315d Mon Sep 17 00:00:00 2001 From: robinjoon Date: Thu, 28 Mar 2024 21:53:34 +0900 Subject: [PATCH 22/45] =?UTF-8?q?feat:=20=ED=84=B4=EC=9D=84=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++ src/main/java/chess/dao/TurnDAO.java | 11 +++ src/main/java/chess/dao/TurnDAOForMysql.java | 70 ++++++++++++++++++ .../java/chess/dao/TurnDAOForMysqlTest.java | 72 +++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 src/main/java/chess/dao/TurnDAO.java create mode 100644 src/main/java/chess/dao/TurnDAOForMysql.java create mode 100644 src/test/java/chess/dao/TurnDAOForMysqlTest.java diff --git a/README.md b/README.md index fe733a6c622..8d7fbcc460f 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ - [x] 점수 출력 기능 - [ ] 데이터 베이스에 저장하는 기능 - [x] 기물을 저장하는 기능 + - [x] 턴을 저장하는 기능 ## 데이터베이스 @@ -128,3 +129,8 @@ CREATE TABLE `pieces_on_board` ( CONSTRAINT `fk-team-pieces_on_board` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ``` + +### 데이터 저장시 고려해야 하는 것 + +1. 데이터가 저장된 적이 없는 경우 혹은 복구를 하지 않겠다고 하는 경우 => 데이터를 모두 지우고, 초기 체스 판을 저장한다. 최초 턴을 white로 지정한다. +2. 말을 움직인 경우, 시작 위치의 말을 지우고, 도착위치의 말을 지운 뒤, 도착 위치로 이동한 기물을 새로 저장한다. 그리고 턴을 바꿔준다. diff --git a/src/main/java/chess/dao/TurnDAO.java b/src/main/java/chess/dao/TurnDAO.java new file mode 100644 index 00000000000..1b748958639 --- /dev/null +++ b/src/main/java/chess/dao/TurnDAO.java @@ -0,0 +1,11 @@ +package chess.dao; + +import chess.domain.piece.Team; + +public interface TurnDAO { + Team select(); + + boolean save(Team team); + + boolean update(Team targetTeam, Team updatedTeam); +} diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java new file mode 100644 index 00000000000..ff47e52fabb --- /dev/null +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -0,0 +1,70 @@ +package chess.dao; + +import chess.domain.piece.Team; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class TurnDAOForMysql implements TurnDAO { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + private final DBConnectionCache dbConnectionCache; + + public TurnDAOForMysql() { + this(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); + } + + private TurnDAOForMysql(String dbUrl, String userName, String password) { + this.dbConnectionCache = new DBConnectionCache(dbUrl, userName, password); + } + + @Override + public Team select() { + Connection connection = dbConnectionCache.getConnection(); + try { + PreparedStatement preparedStatement = connection.prepareStatement( + "select current_team_name from game"); + ResultSet resultSet = preparedStatement.executeQuery(); + resultSet.next(); + if (!(resultSet.isFirst() && resultSet.isLast())) { + throw new IllegalStateException("데이터베이스가 잘못되어있습니다."); + } + String teamName = resultSet.getString(1); + return Team.valueOf(teamName); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean save(Team team) { + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement( + "INSERT INTO game (current_team_name) " + + "SELECT ? " + + "FROM dual " + + "WHERE NOT EXISTS (SELECT * FROM game)"); + preparedStatement.setString(1, team.name()); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean update(Team targetTeam, Team updatedTeam) { + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement( + "update game set current_team_name = ? where current_team_name = ?"); + preparedStatement.setString(1, updatedTeam.name()); + preparedStatement.setString(2, targetTeam.name()); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/chess/dao/TurnDAOForMysqlTest.java b/src/test/java/chess/dao/TurnDAOForMysqlTest.java new file mode 100644 index 00000000000..adc416ca7cd --- /dev/null +++ b/src/test/java/chess/dao/TurnDAOForMysqlTest.java @@ -0,0 +1,72 @@ +package chess.dao; + +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.piece.Team; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TurnDAOForMysqlTest { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + + @BeforeEach + public void initDB() throws SQLException { + DBConnectionCache dbConnectionCache = new DBConnectionCache(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement("delete FROM game"); + preparedStatement.executeUpdate(); + connection.close(); + } + + @Test + @DisplayName("턴을 잘 조회할 수 있는지 검증") + void select() { + TurnDAO turnDAO = new TurnDAOForMysql(); + turnDAO.save(WHITE); + Team selected = turnDAO.select(); + Assertions.assertThat(selected) + .isEqualTo(WHITE); + } + + @Test + @DisplayName("턴을 잘 저장할 수 있는지 검증") + void save() { + TurnDAO turnDAO = new TurnDAOForMysql(); + boolean saveSuccess = turnDAO.save(WHITE); + Assertions.assertThat(saveSuccess) + .isTrue(); + } + + @Test + @DisplayName("턴이 동시에 여러개가 되도록 집어넣을 수 없는지 검증") + void saveFailCauseDuplicateTurn() { + TurnDAO turnDAO = new TurnDAOForMysql(); + boolean saveSuccess = turnDAO.save(WHITE); + boolean expectedToFalse = turnDAO.save(BLACK); + assertAll( + () -> Assertions.assertThat(saveSuccess) + .isTrue(), + () -> Assertions.assertThat(expectedToFalse) + .isFalse() + ); + } + + @Test + @DisplayName("턴을 잘 변경할 수 있는지 검증") + void update() { + TurnDAO turnDAO = new TurnDAOForMysql(); + turnDAO.save(BLACK); + boolean updateSuccess = turnDAO.update(BLACK, WHITE); + Assertions.assertThat(updateSuccess) + .isTrue(); + } +} From d8a41245a5ccb1aea01cfeec73d77de534ee6aa4 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 00:08:34 +0900 Subject: [PATCH 23/45] =?UTF-8?q?feat:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=EC=97=90=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EB=90=9C=20=EA=B2=8C=EC=9E=84=EC=9D=84=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EB=8A=94=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 --- README.md | 3 +- src/main/java/chess/Application.java | 40 +++++++++++++++++-- src/main/java/chess/dao/TurnDAO.java | 3 +- src/main/java/chess/dao/TurnDAOForMysql.java | 7 ++-- .../java/chess/domain/board/ChessBoard.java | 15 ++++--- .../java/chess/domain/game/ChessGame.java | 4 ++ .../java/chess/dao/TurnDAOForMysqlTest.java | 2 +- 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8d7fbcc460f..ae9cd7a8c80 100644 --- a/README.md +++ b/README.md @@ -78,9 +78,10 @@ - [x] 체스 판 출력 기능 - [x] 안내 문구 출력 기능 - [x] 점수 출력 기능 -- [ ] 데이터 베이스에 저장하는 기능 +- [x] 데이터 베이스에 저장하는 기능 - [x] 기물을 저장하는 기능 - [x] 턴을 저장하는 기능 +- [x] 데이터베이스에 저장된 게임을 불러오는 기능 ## 데이터베이스 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index acc19192b84..361d1acc02d 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -1,9 +1,15 @@ package chess; import static chess.domain.game.command.EndCommand.END_COMMAND; +import static chess.domain.piece.PieceMoveResult.FAILURE; import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; +import chess.dao.PiecesOnChessBoardDAO; +import chess.dao.PiecesOnChessBoardDAOForMysql; +import chess.dao.TurnDAO; +import chess.dao.TurnDAOForMysql; +import chess.domain.Position; import chess.domain.game.ChessGame; import chess.domain.game.command.Command; import chess.domain.game.command.MoveCommand; @@ -17,16 +23,31 @@ import chess.view.OutputView; import java.util.List; import java.util.Map; +import java.util.Optional; public class Application { + public static final TurnDAO turnDAO = new TurnDAOForMysql(); + private static final PiecesOnChessBoardDAO piecesOnChessBoardDAO = new PiecesOnChessBoardDAOForMysql(); + public static void main(String[] args) { OutputView.printGuide(); Command startOrEnd = InputView.readStartOrEnd(); if (isEndCommand(startOrEnd)) { return; } - ChessGame chessGame = new ChessGame(); + Optional selected = turnDAO.select(); + if (selected.isPresent()) { + List pieces = piecesOnChessBoardDAO.selectAll(); + Team team = turnDAO.select().orElse(WHITE); + chessGame = new ChessGame(pieces, team); + } + if (selected.isEmpty()) { + for (Piece piece : chessGame.getPiecesOnBoard()) { + piecesOnChessBoardDAO.save(piece); + } + turnDAO.save(WHITE); + } printPiecesOnChessBoard(chessGame); playChess(chessGame); @@ -64,7 +85,7 @@ private static void playChess(ChessGame chessGame) { private static PieceMoveResult playGameOrPrintStatus(Command moveOrStatus, ChessGame chessGame) { if (moveOrStatus.equals(StatusCommand.STATUS_COMMAND)) { printStatus(chessGame); - return PieceMoveResult.FAILURE; + return FAILURE; } return playGame((MoveCommand) moveOrStatus, chessGame); } @@ -79,6 +100,19 @@ private static void printStatus(ChessGame chessGame) { private static PieceMoveResult playGame(MoveCommand moveCommand, ChessGame chessGame) { PieceMoveResult moveResult = chessGame.move(moveCommand); + if (!moveResult.equals(FAILURE)) { + List positions = moveCommand.getOptions(); + Position from = positions.get(0); + Position to = positions.get(1); + piecesOnChessBoardDAO.delete(from); + piecesOnChessBoardDAO.delete(to); + Piece movedPiece = chessGame.getPiecesOnBoard().stream() + .filter(piece -> piece.isOn(to)) + .findFirst().orElseThrow(); + piecesOnChessBoardDAO.save(movedPiece); + Team team = turnDAO.select().orElseThrow(); + turnDAO.update(team, team.otherTeam()); + } printPiecesOnChessBoard(chessGame); printReInputGuideIfNeed(moveResult); printWinnerIfNeed(moveResult); @@ -86,7 +120,7 @@ private static PieceMoveResult playGame(MoveCommand moveCommand, ChessGame chess } private static void printReInputGuideIfNeed(PieceMoveResult moveResult) { - if (moveResult.equals(PieceMoveResult.FAILURE)) { + if (moveResult.equals(FAILURE)) { OutputView.printReInputGuide(); } } diff --git a/src/main/java/chess/dao/TurnDAO.java b/src/main/java/chess/dao/TurnDAO.java index 1b748958639..48a4125a834 100644 --- a/src/main/java/chess/dao/TurnDAO.java +++ b/src/main/java/chess/dao/TurnDAO.java @@ -1,9 +1,10 @@ package chess.dao; import chess.domain.piece.Team; +import java.util.Optional; public interface TurnDAO { - Team select(); + Optional select(); boolean save(Team team); diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index ff47e52fabb..4938a1d593b 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -5,6 +5,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Optional; public class TurnDAOForMysql implements TurnDAO { private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; @@ -21,7 +22,7 @@ private TurnDAOForMysql(String dbUrl, String userName, String password) { } @Override - public Team select() { + public Optional select() { Connection connection = dbConnectionCache.getConnection(); try { PreparedStatement preparedStatement = connection.prepareStatement( @@ -29,10 +30,10 @@ public Team select() { ResultSet resultSet = preparedStatement.executeQuery(); resultSet.next(); if (!(resultSet.isFirst() && resultSet.isLast())) { - throw new IllegalStateException("데이터베이스가 잘못되어있습니다."); + return Optional.empty(); } String teamName = resultSet.getString(1); - return Team.valueOf(teamName); + return Optional.of(Team.valueOf(teamName)); } catch (SQLException e) { throw new RuntimeException(e); } diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index 8fd572becf2..2653a822f0d 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -1,6 +1,7 @@ package chess.domain.board; import static chess.domain.board.InitialPieces.INITIAL_PIECES; +import static chess.domain.piece.Team.WHITE; import chess.domain.Position; import chess.domain.game.PointCalculator; @@ -8,25 +9,29 @@ import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; import chess.domain.piece.Team; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; public class ChessBoard { private final List piecesOnBoard; - private Team currentTeam = Team.WHITE; + private Team currentTeam; public ChessBoard() { this(INITIAL_PIECES); } public ChessBoard(List pieces) { - piecesOnBoard = new ArrayList<>(pieces); + this(pieces, WHITE); + } + + public ChessBoard(List pieces, Team currentTeam) { + this.piecesOnBoard = pieces; + this.currentTeam = currentTeam; } public ChessBoard(Piece... pieces) { - this(List.of(pieces)); + this(List.of(pieces), WHITE); } PieceMoveResult move(Position from, Position to) { @@ -43,7 +48,7 @@ PieceMoveResult move(Position from, Position to) { private PieceMoveResult fixMoveResultWhenGameEnd(Position to, PieceMoveResult moveResult) { boolean gameEnd = isGameEnd(to); - if (gameEnd && currentTeam.equals(Team.WHITE)) { + if (gameEnd && currentTeam.equals(WHITE)) { return PieceMoveResult.WHITE_WIN; } if (gameEnd && currentTeam.equals(Team.BLACK)) { diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 2d2bd25fc57..6ff3286f8d8 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -12,6 +12,10 @@ public class ChessGame { private final ChessBoardForChessGame chessBoard; + public ChessGame(List pieces, Team currentTeam) { + this.chessBoard = new ChessBoardAdaptor(new ChessBoard(pieces, currentTeam)); + } + public ChessGame() { this.chessBoard = new ChessBoardAdaptor(new ChessBoard()); } diff --git a/src/test/java/chess/dao/TurnDAOForMysqlTest.java b/src/test/java/chess/dao/TurnDAOForMysqlTest.java index adc416ca7cd..7d341e50027 100644 --- a/src/test/java/chess/dao/TurnDAOForMysqlTest.java +++ b/src/test/java/chess/dao/TurnDAOForMysqlTest.java @@ -32,7 +32,7 @@ public void initDB() throws SQLException { void select() { TurnDAO turnDAO = new TurnDAOForMysql(); turnDAO.save(WHITE); - Team selected = turnDAO.select(); + Team selected = turnDAO.select().orElseThrow(); Assertions.assertThat(selected) .isEqualTo(WHITE); } From 26e55cabceaf7432fa1972de66934932724cb11b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 15:54:20 +0900 Subject: [PATCH 24/45] =?UTF-8?q?refactor:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20Service=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Application.java | 37 +----- .../java/chess/dao/PiecesOnChessBoardDAO.java | 9 +- .../dao/PiecesOnChessBoardDAOForMysql.java | 81 ++++++++----- src/main/java/chess/dao/TurnDAO.java | 2 + src/main/java/chess/dao/TurnDAOForMysql.java | 5 + .../java/chess/domain/board/ChessBoard.java | 7 +- .../chess/domain/board/ChessBoardAdaptor.java | 5 + .../domain/game/ChessBoardForChessGame.java | 2 + .../java/chess/domain/game/ChessGame.java | 4 + .../service/ChessPersistenceService.java | 70 +++++++++++ .../chess/dao/FakePiecesOnChessBoardDAO.java | 45 +++++++ src/test/java/chess/dao/FakeTurnDAO.java | 37 ++++++ .../PiecesOnChessBoardDAOForMysqlTest.java | 90 -------------- .../java/chess/dao/TurnDAOForMysqlTest.java | 72 ------------ .../service/ChessPersistenceServiceTest.java | 110 ++++++++++++++++++ 15 files changed, 350 insertions(+), 226 deletions(-) create mode 100644 src/main/java/chess/service/ChessPersistenceService.java create mode 100644 src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java create mode 100644 src/test/java/chess/dao/FakeTurnDAO.java delete mode 100644 src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java delete mode 100644 src/test/java/chess/dao/TurnDAOForMysqlTest.java create mode 100644 src/test/java/chess/service/ChessPersistenceServiceTest.java diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 361d1acc02d..045800ee972 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -5,11 +5,6 @@ import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; -import chess.dao.PiecesOnChessBoardDAO; -import chess.dao.PiecesOnChessBoardDAOForMysql; -import chess.dao.TurnDAO; -import chess.dao.TurnDAOForMysql; -import chess.domain.Position; import chess.domain.game.ChessGame; import chess.domain.game.command.Command; import chess.domain.game.command.MoveCommand; @@ -19,15 +14,14 @@ import chess.domain.piece.PieceType; import chess.domain.piece.Team; import chess.dto.PieceDTO; +import chess.service.ChessPersistenceService; import chess.view.InputView; import chess.view.OutputView; import java.util.List; import java.util.Map; -import java.util.Optional; public class Application { - public static final TurnDAO turnDAO = new TurnDAOForMysql(); - private static final PiecesOnChessBoardDAO piecesOnChessBoardDAO = new PiecesOnChessBoardDAOForMysql(); + private static final ChessPersistenceService CHESS_PERSISTENCE_SERVICE = new ChessPersistenceService(); public static void main(String[] args) { OutputView.printGuide(); @@ -35,19 +29,10 @@ public static void main(String[] args) { if (isEndCommand(startOrEnd)) { return; } - ChessGame chessGame = new ChessGame(); - Optional selected = turnDAO.select(); - if (selected.isPresent()) { - List pieces = piecesOnChessBoardDAO.selectAll(); - Team team = turnDAO.select().orElse(WHITE); - chessGame = new ChessGame(pieces, team); - } - if (selected.isEmpty()) { - for (Piece piece : chessGame.getPiecesOnBoard()) { - piecesOnChessBoardDAO.save(piece); - } - turnDAO.save(WHITE); + if (!CHESS_PERSISTENCE_SERVICE.isSaveDataExist()) { + CHESS_PERSISTENCE_SERVICE.saveChessGame(new ChessGame()); } + ChessGame chessGame = CHESS_PERSISTENCE_SERVICE.loadChessGame(); printPiecesOnChessBoard(chessGame); playChess(chessGame); @@ -101,17 +86,7 @@ private static void printStatus(ChessGame chessGame) { private static PieceMoveResult playGame(MoveCommand moveCommand, ChessGame chessGame) { PieceMoveResult moveResult = chessGame.move(moveCommand); if (!moveResult.equals(FAILURE)) { - List positions = moveCommand.getOptions(); - Position from = positions.get(0); - Position to = positions.get(1); - piecesOnChessBoardDAO.delete(from); - piecesOnChessBoardDAO.delete(to); - Piece movedPiece = chessGame.getPiecesOnBoard().stream() - .filter(piece -> piece.isOn(to)) - .findFirst().orElseThrow(); - piecesOnChessBoardDAO.save(movedPiece); - Team team = turnDAO.select().orElseThrow(); - turnDAO.update(team, team.otherTeam()); + CHESS_PERSISTENCE_SERVICE.updateChessGame(chessGame, moveCommand); } printPiecesOnChessBoard(chessGame); printReInputGuideIfNeed(moveResult); diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java index ecd240f8ffe..bb676382174 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java @@ -2,16 +2,17 @@ import chess.domain.Position; import chess.domain.piece.Piece; -import chess.domain.piece.PieceType; -import chess.domain.piece.Team; import java.util.List; public interface PiecesOnChessBoardDAO { + boolean save(Piece piece); + + boolean saveAll(List pieces); + List selectAll(); boolean delete(Position targetPosition); - boolean save(Piece piece); + boolean deleteAll(); - boolean update(Position targetPosition, PieceType pieceType, Team team); } diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java index bab8732e30f..43c19a25496 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; public class PiecesOnChessBoardDAOForMysql implements PiecesOnChessBoardDAO { private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; @@ -32,6 +33,49 @@ public PiecesOnChessBoardDAOForMysql(String dbUrl, String userName, String passw this.dbConnectionCache = new DBConnectionCache(dbUrl, userName, password); } + @Override + public boolean save(Piece piece) { + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement( + "insert into pieces_on_board (piece_type, team_name, position_name) values ( ?, ? ,? )"); + setPieceToPreparedStatement(List.of(piece), preparedStatement); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean saveAll(List pieces) { + String sql = pieces.stream().map(piece -> "( ?, ? ,? )") + .collect(Collectors.joining(",")); + sql = "insert into pieces_on_board (piece_type, team_name, position_name) values " + sql; + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql); + setPieceToPreparedStatement(pieces, preparedStatement); + return preparedStatement.executeUpdate() == pieces.size(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void setPieceToPreparedStatement(List pieces, PreparedStatement preparedStatement) + throws SQLException { + for (int index = 0; index < pieces.size(); index++) { + Piece piece = pieces.get(index); + PieceType pieceType = piece.getPieceType(); + Team team = piece.getTeam(); + int row = piece.getRow(); + int column = piece.getColumn(); + Position position = Position.getInstance(row, column); + preparedStatement.setString((index * 3) + 1, pieceType.name()); + preparedStatement.setString((index * 3) + 2, team.name()); + preparedStatement.setString((index * 3) + 3, position.name()); + } + } + @Override public List selectAll() { Connection connection = dbConnectionCache.getConnection(); @@ -39,8 +83,7 @@ public List selectAll() { PreparedStatement preparedStatement = connection.prepareStatement( "select piece_type, team_name, position_name from pieces_on_board"); ResultSet resultSet = preparedStatement.executeQuery(); - List selected = parsingResultSet(resultSet); - return selected; + return parsingResultSet(resultSet); } catch (SQLException e) { throw new RuntimeException(e); } @@ -86,37 +129,19 @@ public boolean delete(Position targetPosition) { } @Override - public boolean save(Piece piece) { + public boolean deleteAll() { try { Connection connection = dbConnectionCache.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement( - "insert into pieces_on_board (piece_type, team_name, position_name) values ( ?, ? ,? )"); - PieceType pieceType = piece.getPieceType(); - Team team = piece.getTeam(); - int row = piece.getRow(); - int column = piece.getColumn(); - Position position = Position.getInstance(row, column); - preparedStatement.setString(1, pieceType.name()); - preparedStatement.setString(2, team.name()); - preparedStatement.setString(3, position.name()); - return preparedStatement.executeUpdate() == 1; + connection.setAutoCommit(false); + int rowCount = selectAll().size(); + PreparedStatement preparedStatement = connection.prepareStatement("delete from pieces_on_board"); + connection.commit(); + connection.setAutoCommit(true); + return preparedStatement.executeUpdate() == rowCount; } catch (SQLException e) { throw new RuntimeException(e); } } - @Override - public boolean update(Position targetPosition, PieceType pieceType, Team team) { - try { - Connection connection = dbConnectionCache.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement( - "update pieces_on_board set piece_type = ?, team_name = ? where position_name = ?"); - preparedStatement.setString(1, pieceType.name()); - preparedStatement.setString(2, team.name()); - preparedStatement.setString(3, targetPosition.name()); - return preparedStatement.executeUpdate() == 1; - } catch (SQLException e) { - throw new RuntimeException(e); - } - } + } diff --git a/src/main/java/chess/dao/TurnDAO.java b/src/main/java/chess/dao/TurnDAO.java index 48a4125a834..47bbc6fbd72 100644 --- a/src/main/java/chess/dao/TurnDAO.java +++ b/src/main/java/chess/dao/TurnDAO.java @@ -9,4 +9,6 @@ public interface TurnDAO { boolean save(Team team); boolean update(Team targetTeam, Team updatedTeam); + + boolean delete(); } diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index 4938a1d593b..d421190ba36 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -68,4 +68,9 @@ public boolean update(Team targetTeam, Team updatedTeam) { throw new RuntimeException(e); } } + + @Override + public boolean delete() { + return false; + } } diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index 2653a822f0d..f081f1028e4 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -9,6 +9,7 @@ import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; import chess.domain.piece.Team; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -26,7 +27,7 @@ public ChessBoard(List pieces) { } public ChessBoard(List pieces, Team currentTeam) { - this.piecesOnBoard = pieces; + this.piecesOnBoard = new ArrayList<>(pieces); this.currentTeam = currentTeam; } @@ -125,4 +126,8 @@ List getPiecesOnBoard() { double calculatePoint(Team team) { return PointCalculator.calculatePoint(team, piecesOnBoard); } + + Team getCurrentTeam() { + return currentTeam; + } } diff --git a/src/main/java/chess/domain/board/ChessBoardAdaptor.java b/src/main/java/chess/domain/board/ChessBoardAdaptor.java index 8a7146c0bea..30e0878be18 100644 --- a/src/main/java/chess/domain/board/ChessBoardAdaptor.java +++ b/src/main/java/chess/domain/board/ChessBoardAdaptor.java @@ -38,4 +38,9 @@ public Map calculateScores() { double whiteTeamScore = chessBoard.calculatePoint(WHITE); return Map.of(BLACK, blackTeamScore, WHITE, whiteTeamScore); } + + @Override + public Team getCurrentTeam() { + return chessBoard.getCurrentTeam(); + } } diff --git a/src/main/java/chess/domain/game/ChessBoardForChessGame.java b/src/main/java/chess/domain/game/ChessBoardForChessGame.java index a865a233ef4..e511458853b 100644 --- a/src/main/java/chess/domain/game/ChessBoardForChessGame.java +++ b/src/main/java/chess/domain/game/ChessBoardForChessGame.java @@ -13,4 +13,6 @@ public interface ChessBoardForChessGame { List getPiecesOnBoard(); Map calculateScores(); + + Team getCurrentTeam(); } diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 6ff3286f8d8..1fec0d55913 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -31,4 +31,8 @@ public Map calculateScores() { public List getPiecesOnBoard() { return chessBoard.getPiecesOnBoard(); } + + public Team currentTeam() { + return chessBoard.getCurrentTeam(); + } } diff --git a/src/main/java/chess/service/ChessPersistenceService.java b/src/main/java/chess/service/ChessPersistenceService.java new file mode 100644 index 00000000000..f2760b75b6d --- /dev/null +++ b/src/main/java/chess/service/ChessPersistenceService.java @@ -0,0 +1,70 @@ +package chess.service; + +import chess.dao.PiecesOnChessBoardDAO; +import chess.dao.PiecesOnChessBoardDAOForMysql; +import chess.dao.TurnDAO; +import chess.dao.TurnDAOForMysql; +import chess.domain.Position; +import chess.domain.game.ChessGame; +import chess.domain.game.command.MoveCommand; +import chess.domain.piece.Piece; +import chess.domain.piece.Team; +import java.util.List; +import java.util.Optional; + +public class ChessPersistenceService { + private final PiecesOnChessBoardDAO piecesOnChessBoardDAO; + private final TurnDAO turnDAO; + + public ChessPersistenceService() { + this(new PiecesOnChessBoardDAOForMysql(), new TurnDAOForMysql()); + } + + ChessPersistenceService(PiecesOnChessBoardDAO piecesOnChessBoardDAO, TurnDAO turnDAO) { + this.piecesOnChessBoardDAO = piecesOnChessBoardDAO; + this.turnDAO = turnDAO; + } + + public ChessGame loadChessGame() { + if (isSaveDataExist()) { + List pieces = piecesOnChessBoardDAO.selectAll(); + Team currentTeam = turnDAO.select().orElseThrow(); + return new ChessGame(pieces, currentTeam); + } + piecesOnChessBoardDAO.deleteAll(); + turnDAO.delete(); + return new ChessGame(); + } + + public boolean isSaveDataExist() { + Optional selected = turnDAO.select(); + List pieces = piecesOnChessBoardDAO.selectAll(); + return selected.isPresent() && !pieces.isEmpty(); + } + + public boolean saveChessGame(ChessGame chessGame) { + List piecesOnBoard = chessGame.getPiecesOnBoard(); + if (!piecesOnChessBoardDAO.selectAll().isEmpty() && turnDAO.select().isPresent()) { + return false; + } + boolean saveAllPiecesSuccess = piecesOnChessBoardDAO.saveAll(piecesOnBoard); + Team currentTeam = chessGame.currentTeam(); + boolean saveTurnSuccess = turnDAO.save(currentTeam); + return saveAllPiecesSuccess && saveTurnSuccess; + } + + public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { + List positions = moveCommand.getOptions(); + Position from = positions.get(0); + Position to = positions.get(1); + boolean deleteFromSuccess = piecesOnChessBoardDAO.delete(from); + boolean deleteToSuccess = piecesOnChessBoardDAO.delete(to); + Piece movedPiece = chessGame.getPiecesOnBoard().stream() + .filter(piece -> piece.isOn(to)) + .findFirst().orElseThrow(); + boolean saveMovedPieceSuccess = piecesOnChessBoardDAO.save(movedPiece); + Team team = turnDAO.select().orElseThrow(); + boolean updateTurnSuccess = turnDAO.update(team, team.otherTeam()); + return !deleteFromSuccess && deleteToSuccess && saveMovedPieceSuccess && updateTurnSuccess; + } +} diff --git a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java new file mode 100644 index 00000000000..0b90cae8bb0 --- /dev/null +++ b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java @@ -0,0 +1,45 @@ +package chess.dao; + +import chess.domain.Position; +import chess.domain.piece.Piece; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class FakePiecesOnChessBoardDAO implements PiecesOnChessBoardDAO { + private final Set pieces = new HashSet<>(); + + @Override + public boolean save(Piece piece) { + return pieces.add(piece); + } + + @Override + public boolean saveAll(List pieces) { + for (Piece piece : pieces) { + if (this.pieces.contains(piece)) { + return false; + } + } + for (Piece piece : pieces) { + save(piece); + } + return true; + } + + @Override + public List selectAll() { + return pieces.stream().toList(); + } + + @Override + public boolean delete(Position targetPosition) { + return pieces.removeIf(piece -> piece.isOn(targetPosition)); + } + + @Override + public boolean deleteAll() { + pieces.clear(); + return true; + } +} diff --git a/src/test/java/chess/dao/FakeTurnDAO.java b/src/test/java/chess/dao/FakeTurnDAO.java new file mode 100644 index 00000000000..edeeb50da50 --- /dev/null +++ b/src/test/java/chess/dao/FakeTurnDAO.java @@ -0,0 +1,37 @@ +package chess.dao; + +import chess.domain.piece.Team; +import java.util.Optional; + +public class FakeTurnDAO implements TurnDAO { + private Team team; + + @Override + public Optional select() { + return Optional.ofNullable(team); + } + + @Override + public boolean save(Team team) { + if (this.team == null) { + this.team = team; + return true; + } + return false; + } + + @Override + public boolean update(Team targetTeam, Team updatedTeam) { + if (targetTeam.equals(team)) { + team = updatedTeam; + return true; + } + return false; + } + + @Override + public boolean delete() { + team = null; + return true; + } +} diff --git a/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java b/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java deleted file mode 100644 index 0dca41c46d7..00000000000 --- a/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package chess.dao; - -import static chess.domain.Position.A1; -import static chess.domain.Position.A2; -import static chess.domain.Position.A4; -import static chess.domain.piece.Team.BLACK; -import static chess.domain.piece.Team.WHITE; - -import chess.domain.piece.Pawn; -import chess.domain.piece.Piece; -import chess.domain.piece.PieceType; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class PiecesOnChessBoardDAOForMysqlTest { - private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; - private static final String DB_USER_NAME = "user"; - private static final String DB_USER_PASSWORD = "password"; - - @BeforeEach - public void initDB() throws SQLException { - DBConnectionCache dbConnectionCache = new DBConnectionCache(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); - Connection connection = dbConnectionCache.getConnection(); - deleteAllData(connection); - insertInitialData(connection); - connection.close(); - } - - private static void deleteAllData(Connection connection) throws SQLException { - PreparedStatement preparedStatement = connection.prepareStatement("delete FROM pieces_on_board"); - preparedStatement.execute(); - } - - private static void insertInitialData(Connection connection) throws SQLException { - PreparedStatement preparedStatement; - preparedStatement = connection.prepareStatement( - "insert into pieces_on_board(piece_type, team_name, position_name) values ( ? ,? ,? ), (?, ?, ?)"); - preparedStatement.setString(1, "PAWN"); - preparedStatement.setString(2, "WHITE"); - preparedStatement.setString(3, "A1"); - preparedStatement.setString(4, "PAWN"); - preparedStatement.setString(5, "BLACK"); - preparedStatement.setString(6, "A2"); - preparedStatement.execute(); - } - - @Test - @DisplayName("데이터베이스에 저장되어있는 모든 기물이 제대로 조회되는지 검증") - void selectAll() { - PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); - List selected = dao.selectAll(); - Assertions.assertThat(selected) - .containsExactlyInAnyOrder(new Pawn(A1, WHITE), new Pawn(A2, BLACK)); - } - - @Test - @DisplayName("데이터베이스에서 특정 기물을 지울 수 있는지 검증") - void delete() { - PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); - - boolean deleteSuccess = dao.delete(A2); - Assertions.assertThat(deleteSuccess) - .isTrue(); - } - - @Test - @DisplayName("데이터베이스에서 특정 기물을 저장할 수 있는지 검증") - void save() { - PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); - - boolean saveSuccess = dao.save(new Pawn(A4, BLACK)); - Assertions.assertThat(saveSuccess) - .isTrue(); - } - - @Test - @DisplayName("특정 위치의 기물을 다른 것으로 변경할 수 있는지 검증") - void update() { - PiecesOnChessBoardDAO dao = new PiecesOnChessBoardDAOForMysql(); - boolean success = dao.update(A2, PieceType.BISHOP, BLACK); - Assertions.assertThat(success) - .isTrue(); - } -} diff --git a/src/test/java/chess/dao/TurnDAOForMysqlTest.java b/src/test/java/chess/dao/TurnDAOForMysqlTest.java deleted file mode 100644 index 7d341e50027..00000000000 --- a/src/test/java/chess/dao/TurnDAOForMysqlTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package chess.dao; - -import static chess.domain.piece.Team.BLACK; -import static chess.domain.piece.Team.WHITE; -import static org.junit.jupiter.api.Assertions.assertAll; - -import chess.domain.piece.Team; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class TurnDAOForMysqlTest { - private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; - private static final String DB_USER_NAME = "user"; - private static final String DB_USER_PASSWORD = "password"; - - @BeforeEach - public void initDB() throws SQLException { - DBConnectionCache dbConnectionCache = new DBConnectionCache(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); - Connection connection = dbConnectionCache.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement("delete FROM game"); - preparedStatement.executeUpdate(); - connection.close(); - } - - @Test - @DisplayName("턴을 잘 조회할 수 있는지 검증") - void select() { - TurnDAO turnDAO = new TurnDAOForMysql(); - turnDAO.save(WHITE); - Team selected = turnDAO.select().orElseThrow(); - Assertions.assertThat(selected) - .isEqualTo(WHITE); - } - - @Test - @DisplayName("턴을 잘 저장할 수 있는지 검증") - void save() { - TurnDAO turnDAO = new TurnDAOForMysql(); - boolean saveSuccess = turnDAO.save(WHITE); - Assertions.assertThat(saveSuccess) - .isTrue(); - } - - @Test - @DisplayName("턴이 동시에 여러개가 되도록 집어넣을 수 없는지 검증") - void saveFailCauseDuplicateTurn() { - TurnDAO turnDAO = new TurnDAOForMysql(); - boolean saveSuccess = turnDAO.save(WHITE); - boolean expectedToFalse = turnDAO.save(BLACK); - assertAll( - () -> Assertions.assertThat(saveSuccess) - .isTrue(), - () -> Assertions.assertThat(expectedToFalse) - .isFalse() - ); - } - - @Test - @DisplayName("턴을 잘 변경할 수 있는지 검증") - void update() { - TurnDAO turnDAO = new TurnDAOForMysql(); - turnDAO.save(BLACK); - boolean updateSuccess = turnDAO.update(BLACK, WHITE); - Assertions.assertThat(updateSuccess) - .isTrue(); - } -} diff --git a/src/test/java/chess/service/ChessPersistenceServiceTest.java b/src/test/java/chess/service/ChessPersistenceServiceTest.java new file mode 100644 index 00000000000..1d22c0baeb4 --- /dev/null +++ b/src/test/java/chess/service/ChessPersistenceServiceTest.java @@ -0,0 +1,110 @@ +package chess.service; + +import static chess.domain.Position.A1; +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.dao.FakePiecesOnChessBoardDAO; +import chess.dao.FakeTurnDAO; +import chess.domain.game.ChessGame; +import chess.domain.game.command.MoveCommand; +import chess.domain.piece.Pawn; +import chess.domain.piece.Piece; +import chess.domain.piece.Team; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ChessPersistenceServiceTest { + + @Test + @DisplayName("저장된 게임이 있는 경우, 잘 불러오는지 확인") + void loadChessGame() { + FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); + FakeTurnDAO turnDAO = new FakeTurnDAO(); + ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + List pieces = List.of(new Pawn(A1, WHITE)); + Team currentTeam = BLACK; + ChessGame chessGame = new ChessGame(pieces, currentTeam); + chessPersistenceService.saveChessGame(chessGame); + + ChessGame loadedChessGame = chessPersistenceService.loadChessGame(); + List loadedPieces = loadedChessGame.getPiecesOnBoard(); + Team loadedCurrentTeam = loadedChessGame.currentTeam(); + + assertAll( + () -> Assertions.assertThat(loadedPieces).containsExactlyInAnyOrderElementsOf(pieces), + () -> Assertions.assertThat(loadedCurrentTeam).isEqualTo(currentTeam) + ); + + } + + @Test + @DisplayName("저장된 게임이 있는 경우 저장된 게임이 있다고 하는지 검증") + void isSaveDataExistWhenExist() { + FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); + FakeTurnDAO turnDAO = new FakeTurnDAO(); + ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessGame chessGame = new ChessGame(); + chessPersistenceService.saveChessGame(chessGame); + + boolean saveDataExist = chessPersistenceService.isSaveDataExist(); + + Assertions.assertThat(saveDataExist) + .isTrue(); + } + + @Test + @DisplayName("저장된 게임이 없는 경우 저장된 게임이 없다고 하는지 검증") + void isSaveDataExistWhenNotExist() { + FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); + FakeTurnDAO turnDAO = new FakeTurnDAO(); + ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + + boolean saveDataExist = chessPersistenceService.isSaveDataExist(); + + Assertions.assertThat(saveDataExist) + .isFalse(); + } + + @Test + @DisplayName("게임이 잘 저장이 되는지 검증") + void saveChessGame() { + FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); + FakeTurnDAO turnDAO = new FakeTurnDAO(); + ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + boolean saveChessGameSuccess = chessPersistenceService.saveChessGame(new ChessGame()); + Assertions.assertThat(saveChessGameSuccess) + .isTrue(); + } + + @Test + @DisplayName("이미 저장된 게임이 있으면 게임이 저장되지 않는지 검증") + void saveChessGameFail() { + FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); + FakeTurnDAO turnDAO = new FakeTurnDAO(); + ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + chessPersistenceService.saveChessGame(new ChessGame()); + + boolean saveChessGameSuccess = chessPersistenceService.saveChessGame(new ChessGame()); + Assertions.assertThat(saveChessGameSuccess) + .isFalse(); + } + + @Test + @DisplayName("게임의 진행 상황을 저장할 수 있는지 검증") + void updateChessGame() { + FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); + FakeTurnDAO turnDAO = new FakeTurnDAO(); + ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessGame chessGame = new ChessGame(); + chessPersistenceService.saveChessGame(chessGame); + MoveCommand moveCommand = new MoveCommand("a2", "a4"); + chessGame.move(moveCommand); + boolean updateChessGameSuccess = chessPersistenceService.updateChessGame(chessGame, moveCommand); + Assertions.assertThat(updateChessGameSuccess) + .isTrue(); + } +} From aabd4ad8a6ebe49b3c39a6809f8705c218a3047c Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 16:46:23 +0900 Subject: [PATCH 25/45] =?UTF-8?q?chore:=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=AA=85=ED=99=95=ED=95=98=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Application.java | 4 ++-- .../ChessPersistence.java} | 12 ++++-------- .../ChessPersistenceTest.java} | 18 ++++++++---------- 3 files changed, 14 insertions(+), 20 deletions(-) rename src/main/java/chess/{service/ChessPersistenceService.java => dao/ChessPersistence.java} (87%) rename src/test/java/chess/{service/ChessPersistenceServiceTest.java => dao/ChessPersistenceTest.java} (82%) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 045800ee972..9168d12fc44 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -5,6 +5,7 @@ import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; +import chess.dao.ChessPersistence; import chess.domain.game.ChessGame; import chess.domain.game.command.Command; import chess.domain.game.command.MoveCommand; @@ -14,14 +15,13 @@ import chess.domain.piece.PieceType; import chess.domain.piece.Team; import chess.dto.PieceDTO; -import chess.service.ChessPersistenceService; import chess.view.InputView; import chess.view.OutputView; import java.util.List; import java.util.Map; public class Application { - private static final ChessPersistenceService CHESS_PERSISTENCE_SERVICE = new ChessPersistenceService(); + private static final ChessPersistence CHESS_PERSISTENCE_SERVICE = new ChessPersistence(); public static void main(String[] args) { OutputView.printGuide(); diff --git a/src/main/java/chess/service/ChessPersistenceService.java b/src/main/java/chess/dao/ChessPersistence.java similarity index 87% rename from src/main/java/chess/service/ChessPersistenceService.java rename to src/main/java/chess/dao/ChessPersistence.java index f2760b75b6d..7374ec35ecb 100644 --- a/src/main/java/chess/service/ChessPersistenceService.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -1,9 +1,5 @@ -package chess.service; +package chess.dao; -import chess.dao.PiecesOnChessBoardDAO; -import chess.dao.PiecesOnChessBoardDAOForMysql; -import chess.dao.TurnDAO; -import chess.dao.TurnDAOForMysql; import chess.domain.Position; import chess.domain.game.ChessGame; import chess.domain.game.command.MoveCommand; @@ -12,15 +8,15 @@ import java.util.List; import java.util.Optional; -public class ChessPersistenceService { +public class ChessPersistence { private final PiecesOnChessBoardDAO piecesOnChessBoardDAO; private final TurnDAO turnDAO; - public ChessPersistenceService() { + public ChessPersistence() { this(new PiecesOnChessBoardDAOForMysql(), new TurnDAOForMysql()); } - ChessPersistenceService(PiecesOnChessBoardDAO piecesOnChessBoardDAO, TurnDAO turnDAO) { + ChessPersistence(PiecesOnChessBoardDAO piecesOnChessBoardDAO, TurnDAO turnDAO) { this.piecesOnChessBoardDAO = piecesOnChessBoardDAO; this.turnDAO = turnDAO; } diff --git a/src/test/java/chess/service/ChessPersistenceServiceTest.java b/src/test/java/chess/dao/ChessPersistenceTest.java similarity index 82% rename from src/test/java/chess/service/ChessPersistenceServiceTest.java rename to src/test/java/chess/dao/ChessPersistenceTest.java index 1d22c0baeb4..0d8678bc47f 100644 --- a/src/test/java/chess/service/ChessPersistenceServiceTest.java +++ b/src/test/java/chess/dao/ChessPersistenceTest.java @@ -1,12 +1,10 @@ -package chess.service; +package chess.dao; import static chess.domain.Position.A1; import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; import static org.junit.jupiter.api.Assertions.assertAll; -import chess.dao.FakePiecesOnChessBoardDAO; -import chess.dao.FakeTurnDAO; import chess.domain.game.ChessGame; import chess.domain.game.command.MoveCommand; import chess.domain.piece.Pawn; @@ -17,14 +15,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class ChessPersistenceServiceTest { +class ChessPersistenceTest { @Test @DisplayName("저장된 게임이 있는 경우, 잘 불러오는지 확인") void loadChessGame() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); List pieces = List.of(new Pawn(A1, WHITE)); Team currentTeam = BLACK; ChessGame chessGame = new ChessGame(pieces, currentTeam); @@ -46,7 +44,7 @@ void loadChessGame() { void isSaveDataExistWhenExist() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); ChessGame chessGame = new ChessGame(); chessPersistenceService.saveChessGame(chessGame); @@ -61,7 +59,7 @@ void isSaveDataExistWhenExist() { void isSaveDataExistWhenNotExist() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); boolean saveDataExist = chessPersistenceService.isSaveDataExist(); @@ -74,7 +72,7 @@ void isSaveDataExistWhenNotExist() { void saveChessGame() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); boolean saveChessGameSuccess = chessPersistenceService.saveChessGame(new ChessGame()); Assertions.assertThat(saveChessGameSuccess) .isTrue(); @@ -85,7 +83,7 @@ void saveChessGame() { void saveChessGameFail() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); chessPersistenceService.saveChessGame(new ChessGame()); boolean saveChessGameSuccess = chessPersistenceService.saveChessGame(new ChessGame()); @@ -98,7 +96,7 @@ void saveChessGameFail() { void updateChessGame() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistenceService chessPersistenceService = new ChessPersistenceService(piecesOnChessBoardDAO, turnDAO); + ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); ChessGame chessGame = new ChessGame(); chessPersistenceService.saveChessGame(chessGame); MoveCommand moveCommand = new MoveCommand("a2", "a4"); From 119eb9711b4a918a6ab093a2669d0f1f062cf407 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 17:33:56 +0900 Subject: [PATCH 26/45] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=EC=97=90=20=EB=A7=9E=EA=B2=8C=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/chess/dao/PiecesOnChessBoardDAOForMysql.java | 2 -- src/main/java/chess/dao/TurnDAOForMysql.java | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java index 43c19a25496..d0f4576d5a3 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java @@ -142,6 +142,4 @@ public boolean deleteAll() { throw new RuntimeException(e); } } - - } diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index d421190ba36..d5114dd1aea 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -25,8 +25,7 @@ private TurnDAOForMysql(String dbUrl, String userName, String password) { public Optional select() { Connection connection = dbConnectionCache.getConnection(); try { - PreparedStatement preparedStatement = connection.prepareStatement( - "select current_team_name from game"); + PreparedStatement preparedStatement = connection.prepareStatement("select current_team_name from game"); ResultSet resultSet = preparedStatement.executeQuery(); resultSet.next(); if (!(resultSet.isFirst() && resultSet.isLast())) { From 854e4fe8fa0307a212657df2efc5a6e04caefc6b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 17:39:53 +0900 Subject: [PATCH 27/45] =?UTF-8?q?chore:=20=EC=82=AD=EC=A0=9C=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20ToDo=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/domain/piece/PieceMoveResult.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/chess/domain/piece/PieceMoveResult.java b/src/main/java/chess/domain/piece/PieceMoveResult.java index 1a5500a89bb..a4303354949 100644 --- a/src/main/java/chess/domain/piece/PieceMoveResult.java +++ b/src/main/java/chess/domain/piece/PieceMoveResult.java @@ -1,9 +1,8 @@ package chess.domain.piece; public enum PieceMoveResult { - //Todo 게임 종료 여부 분리 SUCCESS, FAILURE, CATCH, WHITE_WIN, BLACK_WIN; - + public boolean isEnd() { return this.equals(BLACK_WIN) || this.equals(WHITE_WIN); } From c0d0554dfb661ad609a360b8b3be95289ecab25b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 17:43:33 +0900 Subject: [PATCH 28/45] =?UTF-8?q?fix:=20=EA=B5=AC=ED=98=84=EC=9D=B4=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=EB=90=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/dao/TurnDAOForMysql.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index d5114dd1aea..f99dfb4ba77 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -70,6 +70,12 @@ public boolean update(Team targetTeam, Team updatedTeam) { @Override public boolean delete() { - return false; + try { + Connection connection = dbConnectionCache.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement("delete from game"); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } } } From 79f65b209b33bd1277fc7aa5089e9e1d09dcef52 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 17:47:24 +0900 Subject: [PATCH 29/45] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/chess/dao/PiecesOnChessBoardDAO.java | 2 +- .../dao/PiecesOnChessBoardDAOForMysql.java | 38 +++++++++---------- src/main/java/chess/dao/TurnDAO.java | 2 +- src/main/java/chess/dao/TurnDAOForMysql.java | 4 +- .../chess/dao/FakePiecesOnChessBoardDAO.java | 3 +- src/test/java/chess/dao/FakeTurnDAO.java | 3 +- 6 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java index bb676382174..2675b55a05a 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java @@ -13,6 +13,6 @@ public interface PiecesOnChessBoardDAO { boolean delete(Position targetPosition); - boolean deleteAll(); + void deleteAll(); } diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java index d0f4576d5a3..5d0d3c41c5d 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java @@ -61,21 +61,6 @@ public boolean saveAll(List pieces) { } } - private static void setPieceToPreparedStatement(List pieces, PreparedStatement preparedStatement) - throws SQLException { - for (int index = 0; index < pieces.size(); index++) { - Piece piece = pieces.get(index); - PieceType pieceType = piece.getPieceType(); - Team team = piece.getTeam(); - int row = piece.getRow(); - int column = piece.getColumn(); - Position position = Position.getInstance(row, column); - preparedStatement.setString((index * 3) + 1, pieceType.name()); - preparedStatement.setString((index * 3) + 2, team.name()); - preparedStatement.setString((index * 3) + 3, position.name()); - } - } - @Override public List selectAll() { Connection connection = dbConnectionCache.getConnection(); @@ -129,17 +114,28 @@ public boolean delete(Position targetPosition) { } @Override - public boolean deleteAll() { + public void deleteAll() { try { Connection connection = dbConnectionCache.getConnection(); - connection.setAutoCommit(false); - int rowCount = selectAll().size(); PreparedStatement preparedStatement = connection.prepareStatement("delete from pieces_on_board"); - connection.commit(); - connection.setAutoCommit(true); - return preparedStatement.executeUpdate() == rowCount; + preparedStatement.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } } + + private static void setPieceToPreparedStatement(List pieces, PreparedStatement preparedStatement) + throws SQLException { + for (int index = 0; index < pieces.size(); index++) { + Piece piece = pieces.get(index); + PieceType pieceType = piece.getPieceType(); + Team team = piece.getTeam(); + int row = piece.getRow(); + int column = piece.getColumn(); + Position position = Position.getInstance(row, column); + preparedStatement.setString((index * 3) + 1, pieceType.name()); + preparedStatement.setString((index * 3) + 2, team.name()); + preparedStatement.setString((index * 3) + 3, position.name()); + } + } } diff --git a/src/main/java/chess/dao/TurnDAO.java b/src/main/java/chess/dao/TurnDAO.java index 47bbc6fbd72..f08379f8514 100644 --- a/src/main/java/chess/dao/TurnDAO.java +++ b/src/main/java/chess/dao/TurnDAO.java @@ -10,5 +10,5 @@ public interface TurnDAO { boolean update(Team targetTeam, Team updatedTeam); - boolean delete(); + void delete(); } diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index f99dfb4ba77..e079ef23097 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -69,11 +69,11 @@ public boolean update(Team targetTeam, Team updatedTeam) { } @Override - public boolean delete() { + public void delete() { try { Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("delete from game"); - return preparedStatement.executeUpdate() == 1; + preparedStatement.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } diff --git a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java index 0b90cae8bb0..becef256718 100644 --- a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java +++ b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java @@ -38,8 +38,7 @@ public boolean delete(Position targetPosition) { } @Override - public boolean deleteAll() { + public void deleteAll() { pieces.clear(); - return true; } } diff --git a/src/test/java/chess/dao/FakeTurnDAO.java b/src/test/java/chess/dao/FakeTurnDAO.java index edeeb50da50..fb1d50148e6 100644 --- a/src/test/java/chess/dao/FakeTurnDAO.java +++ b/src/test/java/chess/dao/FakeTurnDAO.java @@ -30,8 +30,7 @@ public boolean update(Team targetTeam, Team updatedTeam) { } @Override - public boolean delete() { + public void delete() { team = null; - return true; } } From 53d8499f31b6eb3bc1fc338e948d72213eab7a51 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Fri, 29 Mar 2024 17:50:50 +0900 Subject: [PATCH 30/45] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?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/chess/dao/ChessPersistence.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/chess/dao/ChessPersistence.java b/src/main/java/chess/dao/ChessPersistence.java index 7374ec35ecb..f8442207198 100644 --- a/src/main/java/chess/dao/ChessPersistence.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -55,12 +55,16 @@ public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { Position to = positions.get(1); boolean deleteFromSuccess = piecesOnChessBoardDAO.delete(from); boolean deleteToSuccess = piecesOnChessBoardDAO.delete(to); - Piece movedPiece = chessGame.getPiecesOnBoard().stream() - .filter(piece -> piece.isOn(to)) - .findFirst().orElseThrow(); + Piece movedPiece = findMovedPiece(chessGame, to); boolean saveMovedPieceSuccess = piecesOnChessBoardDAO.save(movedPiece); Team team = turnDAO.select().orElseThrow(); boolean updateTurnSuccess = turnDAO.update(team, team.otherTeam()); return !deleteFromSuccess && deleteToSuccess && saveMovedPieceSuccess && updateTurnSuccess; } + + private Piece findMovedPiece(ChessGame chessGame, Position to) { + return chessGame.getPiecesOnBoard().stream() + .filter(piece -> piece.isOn(to)) + .findFirst().orElseThrow(); + } } From 564e2ed869b3d219c7b8bf1c664674d7048c8b9b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Sat, 30 Mar 2024 21:33:49 +0900 Subject: [PATCH 31/45] =?UTF-8?q?docs:=204=EB=8B=A8=EA=B3=84=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20=EB=B0=98=EC=98=81=20=EC=98=88=EC=A0=95=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index ae9cd7a8c80..784d44bd4e5 100644 --- a/README.md +++ b/README.md @@ -135,3 +135,17 @@ CREATE TABLE `pieces_on_board` ( 1. 데이터가 저장된 적이 없는 경우 혹은 복구를 하지 않겠다고 하는 경우 => 데이터를 모두 지우고, 초기 체스 판을 저장한다. 최초 턴을 white로 지정한다. 2. 말을 움직인 경우, 시작 위치의 말을 지우고, 도착위치의 말을 지운 뒤, 도착 위치로 이동한 기물을 새로 저장한다. 그리고 턴을 바꿔준다. + +## 피드백 반영 예정 목록 + +### DB 관련 + +- [ ] 트랜잭션 적용 +- [ ] TurnDAO에서 비즈니스 로직 상위로 이동 +- [ ] DAO에 boolean을 반환하는 메서드 추가 +- [ ] 구체적인 예외를 던지도록 수정 +- [ ] DAO 테스트 추가 + +### 도메인 로직 관련 + +- [ ] 킹이 잡히는 경우 실제로 킹이 보드에서 삭제되지 않는 부분 수정 From 8dcf91ee839fcaa4422d44ad41093fa60f8e30d9 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Sat, 30 Mar 2024 22:00:44 +0900 Subject: [PATCH 32/45] =?UTF-8?q?fix:=20=ED=82=B9=EC=9D=B4=20=EC=9E=A1?= =?UTF-8?q?=ED=9E=88=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=8B=A4=EC=A0=9C?= =?UTF-8?q?=EB=A1=9C=20=ED=82=B9=EC=9D=B4=20=EB=B3=B4=EB=93=9C=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=82=AD=EC=A0=9C=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=20=EB=B6=80=EB=B6=84=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 +- src/main/java/chess/domain/board/ChessBoard.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 784d44bd4e5..7a4f6522f54 100644 --- a/README.md +++ b/README.md @@ -148,4 +148,4 @@ CREATE TABLE `pieces_on_board` ( ### 도메인 로직 관련 -- [ ] 킹이 잡히는 경우 실제로 킹이 보드에서 삭제되지 않는 부분 수정 +- [x] 킹이 잡히는 경우 실제로 킹이 보드에서 삭제되지 않는 부분 수정 diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index f081f1028e4..8b26cc85485 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -41,8 +41,8 @@ PieceMoveResult move(Position from, Position to) { } Piece piece = findPiece(from); PieceMoveResult moveResult = piece.move(to, this); - moveResult = fixMoveResultWhenGameEnd(to, moveResult); removePieceIfCaught(to, moveResult); + moveResult = fixMoveResultWhenGameEnd(to, moveResult); changeCurrentTeamIfNotFail(moveResult); return moveResult; } @@ -69,10 +69,6 @@ private boolean isKing(Piece piece) { return piece.getPieceType().equals(PieceType.KING); } - private boolean isOtherTeam(Piece piece) { - return piece.isTeamWith(currentTeam.otherTeam()); - } - private boolean isEmptyPosition(Position from) { Optional optionalPiece = piecesOnBoard.stream() .filter(piece -> piece.isOn(from)) @@ -107,6 +103,10 @@ private void removeDeadPiece(Position to) { piecesOnBoard.remove(needToRemovePiece); } + private boolean isOtherTeam(Piece piece) { + return piece.isTeamWith(currentTeam.otherTeam()); + } + private void changeCurrentTeamIfNotFail(PieceMoveResult moveResult) { if (!moveResult.equals(PieceMoveResult.FAILURE)) { currentTeam = currentTeam.otherTeam(); From 36d14d8afa5f4c437b152bf48b6bc97f7c300b7d Mon Sep 17 00:00:00 2001 From: robinjoon Date: Sat, 30 Mar 2024 22:06:07 +0900 Subject: [PATCH 33/45] =?UTF-8?q?docs:=20=EC=88=98=EC=A0=95=ED=95=B4?= =?UTF-8?q?=EC=95=BC=20=ED=95=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7a4f6522f54..8e7f554d4a9 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,10 @@ CREATE TABLE `pieces_on_board` ( - [ ] DAO에 boolean을 반환하는 메서드 추가 - [ ] 구체적인 예외를 던지도록 수정 - [ ] DAO 테스트 추가 +- [ ] 킹이 잡힌 경우 데이터를 초기화하도록 수정 +- [ ] 폰이 데이터베이스에서 로드된 뒤에 폰이 2칸 움직일 수 있는 버그 수정 ### 도메인 로직 관련 - [x] 킹이 잡히는 경우 실제로 킹이 보드에서 삭제되지 않는 부분 수정 + From af36b71a8257f7f693a1ff46439a7f87c9388134 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Sat, 30 Mar 2024 22:47:09 +0900 Subject: [PATCH 34/45] =?UTF-8?q?feat:=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/chess/dao/ChessPersistence.java | 65 +++- .../java/chess/dao/DBConnectionCache.java | 41 +-- .../chess/dao/MysqlDBConnectionCache.java | 52 +++ .../java/chess/dao/PiecesOnChessBoardDAO.java | 11 +- .../dao/PiecesOnChessBoardDAOForMysql.java | 27 +- src/main/java/chess/dao/TurnDAO.java | 9 +- src/main/java/chess/dao/TurnDAOForMysql.java | 24 +- .../java/chess/dao/ChessPersistenceTest.java | 34 +- .../java/chess/dao/FakeDBConnectionCache.java | 305 ++++++++++++++++++ .../chess/dao/FakePiecesOnChessBoardDAO.java | 13 +- src/test/java/chess/dao/FakeTurnDAO.java | 9 +- 12 files changed, 458 insertions(+), 134 deletions(-) create mode 100644 src/main/java/chess/dao/MysqlDBConnectionCache.java create mode 100644 src/test/java/chess/dao/FakeDBConnectionCache.java diff --git a/README.md b/README.md index 8e7f554d4a9..dc481d123a6 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ CREATE TABLE `pieces_on_board` ( ### DB 관련 -- [ ] 트랜잭션 적용 +- [x] 트랜잭션 적용 - [ ] TurnDAO에서 비즈니스 로직 상위로 이동 - [ ] DAO에 boolean을 반환하는 메서드 추가 - [ ] 구체적인 예외를 던지도록 수정 diff --git a/src/main/java/chess/dao/ChessPersistence.java b/src/main/java/chess/dao/ChessPersistence.java index f8442207198..6765050073e 100644 --- a/src/main/java/chess/dao/ChessPersistence.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -5,60 +5,93 @@ import chess.domain.game.command.MoveCommand; import chess.domain.piece.Piece; import chess.domain.piece.Team; +import java.sql.Connection; +import java.sql.SQLException; import java.util.List; import java.util.Optional; public class ChessPersistence { private final PiecesOnChessBoardDAO piecesOnChessBoardDAO; private final TurnDAO turnDAO; + private final DBConnectionCache dbConnectionCache; public ChessPersistence() { - this(new PiecesOnChessBoardDAOForMysql(), new TurnDAOForMysql()); + this(new PiecesOnChessBoardDAOForMysql(), new TurnDAOForMysql(), new MysqlDBConnectionCache()); } - ChessPersistence(PiecesOnChessBoardDAO piecesOnChessBoardDAO, TurnDAO turnDAO) { + ChessPersistence(PiecesOnChessBoardDAO piecesOnChessBoardDAO, TurnDAO turnDAO, + DBConnectionCache dbConnectionCache) { this.piecesOnChessBoardDAO = piecesOnChessBoardDAO; this.turnDAO = turnDAO; + this.dbConnectionCache = dbConnectionCache; } public ChessGame loadChessGame() { + Connection connection = dbConnectionCache.getConnection(); + startTransaction(connection); if (isSaveDataExist()) { - List pieces = piecesOnChessBoardDAO.selectAll(); - Team currentTeam = turnDAO.select().orElseThrow(); + List pieces = piecesOnChessBoardDAO.selectAll(connection); + Team currentTeam = turnDAO.select(connection).orElseThrow(); return new ChessGame(pieces, currentTeam); } - piecesOnChessBoardDAO.deleteAll(); - turnDAO.delete(); + piecesOnChessBoardDAO.deleteAll(connection); + turnDAO.delete(connection); + commitTransaction(connection); return new ChessGame(); } + private void startTransaction(Connection connection) { + try { + connection.setAutoCommit(false); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + public boolean isSaveDataExist() { - Optional selected = turnDAO.select(); - List pieces = piecesOnChessBoardDAO.selectAll(); + Connection connection = dbConnectionCache.getConnection(); + startTransaction(connection); + Optional selected = turnDAO.select(connection); + List pieces = piecesOnChessBoardDAO.selectAll(connection); + commitTransaction(connection); return selected.isPresent() && !pieces.isEmpty(); } + private void commitTransaction(Connection connection) { + try { + connection.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + public boolean saveChessGame(ChessGame chessGame) { + Connection connection = dbConnectionCache.getConnection(); List piecesOnBoard = chessGame.getPiecesOnBoard(); - if (!piecesOnChessBoardDAO.selectAll().isEmpty() && turnDAO.select().isPresent()) { + startTransaction(connection); + if (!piecesOnChessBoardDAO.selectAll(connection).isEmpty() && turnDAO.select(connection).isPresent()) { return false; } - boolean saveAllPiecesSuccess = piecesOnChessBoardDAO.saveAll(piecesOnBoard); + boolean saveAllPiecesSuccess = piecesOnChessBoardDAO.saveAll(piecesOnBoard, connection); Team currentTeam = chessGame.currentTeam(); - boolean saveTurnSuccess = turnDAO.save(currentTeam); + boolean saveTurnSuccess = turnDAO.save(currentTeam, connection); + commitTransaction(connection); return saveAllPiecesSuccess && saveTurnSuccess; } public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { + Connection connection = dbConnectionCache.getConnection(); List positions = moveCommand.getOptions(); Position from = positions.get(0); Position to = positions.get(1); - boolean deleteFromSuccess = piecesOnChessBoardDAO.delete(from); - boolean deleteToSuccess = piecesOnChessBoardDAO.delete(to); + startTransaction(connection); + boolean deleteFromSuccess = piecesOnChessBoardDAO.delete(from, connection); + boolean deleteToSuccess = piecesOnChessBoardDAO.delete(to, connection); Piece movedPiece = findMovedPiece(chessGame, to); - boolean saveMovedPieceSuccess = piecesOnChessBoardDAO.save(movedPiece); - Team team = turnDAO.select().orElseThrow(); - boolean updateTurnSuccess = turnDAO.update(team, team.otherTeam()); + boolean saveMovedPieceSuccess = piecesOnChessBoardDAO.save(movedPiece, connection); + Team team = turnDAO.select(connection).orElseThrow(); + boolean updateTurnSuccess = turnDAO.update(team, team.otherTeam(), connection); + commitTransaction(connection); return !deleteFromSuccess && deleteToSuccess && saveMovedPieceSuccess && updateTurnSuccess; } diff --git a/src/main/java/chess/dao/DBConnectionCache.java b/src/main/java/chess/dao/DBConnectionCache.java index 0f8b838bb1a..0d6a736da12 100644 --- a/src/main/java/chess/dao/DBConnectionCache.java +++ b/src/main/java/chess/dao/DBConnectionCache.java @@ -1,44 +1,7 @@ package chess.dao; import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -public class DBConnectionCache { - private final DBConnectionParameters dbConnectionParameters; - private Connection connection; - - public DBConnectionCache(String url, String userName, String password) { - dbConnectionParameters = new DBConnectionParameters(url, userName, password); - connection = createConnection(dbConnectionParameters); - } - - private Connection createConnection(DBConnectionParameters dbConnectionParameters) { - String url = dbConnectionParameters.url; - String userName = dbConnectionParameters.userName; - String password = dbConnectionParameters.password; - try { - return DriverManager.getConnection(url, userName, password); - } catch (SQLException e) { - throw new RuntimeException("DB 접속 에러", e); - } - } - - public Connection getConnection() { - try { - return getConnectionCanThrow(); - } catch (SQLException e) { - throw new RuntimeException("DB 접속 에러"); - } - } - - private Connection getConnectionCanThrow() throws SQLException { - if (!connection.isValid(1)) { - connection = createConnection(dbConnectionParameters); - } - return connection; - } - - private record DBConnectionParameters(String url, String userName, String password) { - } +public interface DBConnectionCache { + Connection getConnection(); } diff --git a/src/main/java/chess/dao/MysqlDBConnectionCache.java b/src/main/java/chess/dao/MysqlDBConnectionCache.java new file mode 100644 index 00000000000..4e4c78521e6 --- /dev/null +++ b/src/main/java/chess/dao/MysqlDBConnectionCache.java @@ -0,0 +1,52 @@ +package chess.dao; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class MysqlDBConnectionCache implements DBConnectionCache { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + private final DBConnectionParameters dbConnectionParameters; + private Connection connection; + + public MysqlDBConnectionCache() { + this(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); + } + + public MysqlDBConnectionCache(String url, String userName, String password) { + dbConnectionParameters = new DBConnectionParameters(url, userName, password); + connection = createConnection(dbConnectionParameters); + } + + private Connection createConnection(DBConnectionParameters dbConnectionParameters) { + String url = dbConnectionParameters.url; + String userName = dbConnectionParameters.userName; + String password = dbConnectionParameters.password; + try { + return DriverManager.getConnection(url, userName, password); + } catch (SQLException e) { + throw new RuntimeException("DB 접속 에러", e); + } + } + + @Override + public Connection getConnection() { + try { + return getConnectionCanThrow(); + } catch (SQLException e) { + throw new RuntimeException("DB 접속 에러"); + } + } + + private Connection getConnectionCanThrow() throws SQLException { + if (!connection.isValid(1)) { + connection = createConnection(dbConnectionParameters); + } + return connection; + } + + private record DBConnectionParameters(String url, String userName, String password) { + } +} diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java index 2675b55a05a..d9a430f6102 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java @@ -2,17 +2,18 @@ import chess.domain.Position; import chess.domain.piece.Piece; +import java.sql.Connection; import java.util.List; public interface PiecesOnChessBoardDAO { - boolean save(Piece piece); + boolean save(Piece piece, Connection connection); - boolean saveAll(List pieces); + boolean saveAll(List pieces, Connection connection); - List selectAll(); + List selectAll(Connection connection); - boolean delete(Position targetPosition); + boolean delete(Position targetPosition, Connection connection); - void deleteAll(); + void deleteAll(Connection connection); } diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java index 5d0d3c41c5d..0ef771d5523 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java @@ -20,23 +20,10 @@ import java.util.stream.Collectors; public class PiecesOnChessBoardDAOForMysql implements PiecesOnChessBoardDAO { - private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; - private static final String DB_USER_NAME = "user"; - private static final String DB_USER_PASSWORD = "password"; - private final DBConnectionCache dbConnectionCache; - - public PiecesOnChessBoardDAOForMysql() { - this(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); - } - - public PiecesOnChessBoardDAOForMysql(String dbUrl, String userName, String password) { - this.dbConnectionCache = new DBConnectionCache(dbUrl, userName, password); - } @Override - public boolean save(Piece piece) { + public boolean save(Piece piece, Connection connection) { try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement( "insert into pieces_on_board (piece_type, team_name, position_name) values ( ?, ? ,? )"); setPieceToPreparedStatement(List.of(piece), preparedStatement); @@ -47,12 +34,11 @@ public boolean save(Piece piece) { } @Override - public boolean saveAll(List pieces) { + public boolean saveAll(List pieces, Connection connection) { String sql = pieces.stream().map(piece -> "( ?, ? ,? )") .collect(Collectors.joining(",")); sql = "insert into pieces_on_board (piece_type, team_name, position_name) values " + sql; try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement(sql); setPieceToPreparedStatement(pieces, preparedStatement); return preparedStatement.executeUpdate() == pieces.size(); @@ -62,8 +48,7 @@ public boolean saveAll(List pieces) { } @Override - public List selectAll() { - Connection connection = dbConnectionCache.getConnection(); + public List selectAll(Connection connection) { try { PreparedStatement preparedStatement = connection.prepareStatement( "select piece_type, team_name, position_name from pieces_on_board"); @@ -101,9 +86,8 @@ private Piece mapToPiece(PieceType pieceType, Team team, Position position) { } @Override - public boolean delete(Position targetPosition) { + public boolean delete(Position targetPosition, Connection connection) { try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement( "delete from pieces_on_board where position_name = ?"); preparedStatement.setString(1, targetPosition.name()); @@ -114,9 +98,8 @@ public boolean delete(Position targetPosition) { } @Override - public void deleteAll() { + public void deleteAll(Connection connection) { try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("delete from pieces_on_board"); preparedStatement.executeUpdate(); } catch (SQLException e) { diff --git a/src/main/java/chess/dao/TurnDAO.java b/src/main/java/chess/dao/TurnDAO.java index f08379f8514..8ab79437c82 100644 --- a/src/main/java/chess/dao/TurnDAO.java +++ b/src/main/java/chess/dao/TurnDAO.java @@ -1,14 +1,15 @@ package chess.dao; import chess.domain.piece.Team; +import java.sql.Connection; import java.util.Optional; public interface TurnDAO { - Optional select(); + Optional select(Connection connection); - boolean save(Team team); + boolean save(Team team, Connection connection); - boolean update(Team targetTeam, Team updatedTeam); + boolean update(Team targetTeam, Team updatedTeam, Connection connection); - void delete(); + void delete(Connection connection); } diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index e079ef23097..29db2ace19d 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -8,22 +8,9 @@ import java.util.Optional; public class TurnDAOForMysql implements TurnDAO { - private static final String DB_URL = "jdbc:mysql://localhost:13306/chess?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; - private static final String DB_USER_NAME = "user"; - private static final String DB_USER_PASSWORD = "password"; - private final DBConnectionCache dbConnectionCache; - - public TurnDAOForMysql() { - this(DB_URL, DB_USER_NAME, DB_USER_PASSWORD); - } - - private TurnDAOForMysql(String dbUrl, String userName, String password) { - this.dbConnectionCache = new DBConnectionCache(dbUrl, userName, password); - } @Override - public Optional select() { - Connection connection = dbConnectionCache.getConnection(); + public Optional select(Connection connection) { try { PreparedStatement preparedStatement = connection.prepareStatement("select current_team_name from game"); ResultSet resultSet = preparedStatement.executeQuery(); @@ -39,9 +26,8 @@ public Optional select() { } @Override - public boolean save(Team team) { + public boolean save(Team team, Connection connection) { try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement( "INSERT INTO game (current_team_name) " + "SELECT ? " @@ -55,9 +41,8 @@ public boolean save(Team team) { } @Override - public boolean update(Team targetTeam, Team updatedTeam) { + public boolean update(Team targetTeam, Team updatedTeam, Connection connection) { try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement( "update game set current_team_name = ? where current_team_name = ?"); preparedStatement.setString(1, updatedTeam.name()); @@ -69,9 +54,8 @@ public boolean update(Team targetTeam, Team updatedTeam) { } @Override - public void delete() { + public void delete(Connection connection) { try { - Connection connection = dbConnectionCache.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("delete from game"); preparedStatement.executeUpdate(); } catch (SQLException e) { diff --git a/src/test/java/chess/dao/ChessPersistenceTest.java b/src/test/java/chess/dao/ChessPersistenceTest.java index 0d8678bc47f..9bcfd2176bc 100644 --- a/src/test/java/chess/dao/ChessPersistenceTest.java +++ b/src/test/java/chess/dao/ChessPersistenceTest.java @@ -16,19 +16,20 @@ import org.junit.jupiter.api.Test; class ChessPersistenceTest { + private final FakeDBConnectionCache dbConnectionCache = new FakeDBConnectionCache(); @Test @DisplayName("저장된 게임이 있는 경우, 잘 불러오는지 확인") void loadChessGame() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); + ChessPersistence persistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO, dbConnectionCache); List pieces = List.of(new Pawn(A1, WHITE)); Team currentTeam = BLACK; ChessGame chessGame = new ChessGame(pieces, currentTeam); - chessPersistenceService.saveChessGame(chessGame); + persistenceService.saveChessGame(chessGame); - ChessGame loadedChessGame = chessPersistenceService.loadChessGame(); + ChessGame loadedChessGame = persistenceService.loadChessGame(); List loadedPieces = loadedChessGame.getPiecesOnBoard(); Team loadedCurrentTeam = loadedChessGame.currentTeam(); @@ -36,7 +37,6 @@ void loadChessGame() { () -> Assertions.assertThat(loadedPieces).containsExactlyInAnyOrderElementsOf(pieces), () -> Assertions.assertThat(loadedCurrentTeam).isEqualTo(currentTeam) ); - } @Test @@ -44,11 +44,11 @@ void loadChessGame() { void isSaveDataExistWhenExist() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); + ChessPersistence persistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO, dbConnectionCache); ChessGame chessGame = new ChessGame(); - chessPersistenceService.saveChessGame(chessGame); + persistenceService.saveChessGame(chessGame); - boolean saveDataExist = chessPersistenceService.isSaveDataExist(); + boolean saveDataExist = persistenceService.isSaveDataExist(); Assertions.assertThat(saveDataExist) .isTrue(); @@ -59,9 +59,9 @@ void isSaveDataExistWhenExist() { void isSaveDataExistWhenNotExist() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); + ChessPersistence persistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO, dbConnectionCache); - boolean saveDataExist = chessPersistenceService.isSaveDataExist(); + boolean saveDataExist = persistenceService.isSaveDataExist(); Assertions.assertThat(saveDataExist) .isFalse(); @@ -72,8 +72,8 @@ void isSaveDataExistWhenNotExist() { void saveChessGame() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); - boolean saveChessGameSuccess = chessPersistenceService.saveChessGame(new ChessGame()); + ChessPersistence persistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO, dbConnectionCache); + boolean saveChessGameSuccess = persistenceService.saveChessGame(new ChessGame()); Assertions.assertThat(saveChessGameSuccess) .isTrue(); } @@ -83,10 +83,10 @@ void saveChessGame() { void saveChessGameFail() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); - chessPersistenceService.saveChessGame(new ChessGame()); + ChessPersistence persistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO, dbConnectionCache); + persistenceService.saveChessGame(new ChessGame()); - boolean saveChessGameSuccess = chessPersistenceService.saveChessGame(new ChessGame()); + boolean saveChessGameSuccess = persistenceService.saveChessGame(new ChessGame()); Assertions.assertThat(saveChessGameSuccess) .isFalse(); } @@ -96,12 +96,12 @@ void saveChessGameFail() { void updateChessGame() { FakePiecesOnChessBoardDAO piecesOnChessBoardDAO = new FakePiecesOnChessBoardDAO(); FakeTurnDAO turnDAO = new FakeTurnDAO(); - ChessPersistence chessPersistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO); + ChessPersistence persistenceService = new ChessPersistence(piecesOnChessBoardDAO, turnDAO, dbConnectionCache); ChessGame chessGame = new ChessGame(); - chessPersistenceService.saveChessGame(chessGame); + persistenceService.saveChessGame(chessGame); MoveCommand moveCommand = new MoveCommand("a2", "a4"); chessGame.move(moveCommand); - boolean updateChessGameSuccess = chessPersistenceService.updateChessGame(chessGame, moveCommand); + boolean updateChessGameSuccess = persistenceService.updateChessGame(chessGame, moveCommand); Assertions.assertThat(updateChessGameSuccess) .isTrue(); } diff --git a/src/test/java/chess/dao/FakeDBConnectionCache.java b/src/test/java/chess/dao/FakeDBConnectionCache.java new file mode 100644 index 00000000000..ff6189d6fd8 --- /dev/null +++ b/src/test/java/chess/dao/FakeDBConnectionCache.java @@ -0,0 +1,305 @@ +package chess.dao; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +public class FakeDBConnectionCache implements DBConnectionCache { + @Override + public Connection getConnection() { + return new FakeConnection(); + } + + private static class FakeConnection implements Connection { + + @Override + public Statement createStatement() throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + return null; + } + + @Override + public String nativeSQL(String sql) throws SQLException { + return null; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + + } + + + + @Override + public boolean getAutoCommit() throws SQLException { + return false; + } + + @Override + public void commit() throws SQLException { + + } + + @Override + public void rollback() throws SQLException { + + } + + @Override + public void close() throws SQLException { + + } + + @Override + public boolean isClosed() throws SQLException { + return false; + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return null; + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public void setCatalog(String catalog) throws SQLException { + + } + + @Override + public String getCatalog() throws SQLException { + return null; + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + + } + + @Override + public int getTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return null; + } + + @Override + public void clearWarnings() throws SQLException { + + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + return null; + } + + @Override + public Map> getTypeMap() throws SQLException { + return null; + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + + } + + @Override + public void setHoldability(int holdability) throws SQLException { + + } + + @Override + public int getHoldability() throws SQLException { + return 0; + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return null; + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + return null; + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return null; + } + + @Override + public Clob createClob() throws SQLException { + return null; + } + + @Override + public Blob createBlob() throws SQLException { + return null; + } + + @Override + public NClob createNClob() throws SQLException { + return null; + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return null; + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return false; + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + + } + + @Override + public String getClientInfo(String name) throws SQLException { + return null; + } + + @Override + public Properties getClientInfo() throws SQLException { + return null; + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return null; + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return null; + } + + @Override + public void setSchema(String schema) throws SQLException { + + } + + @Override + public String getSchema() throws SQLException { + return null; + } + + @Override + public void abort(Executor executor) throws SQLException { + + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + + } + + @Override + public int getNetworkTimeout() throws SQLException { + return 0; + } + } +} diff --git a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java index becef256718..2178523c8a7 100644 --- a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java +++ b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java @@ -2,6 +2,7 @@ import chess.domain.Position; import chess.domain.piece.Piece; +import java.sql.Connection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -10,35 +11,35 @@ public class FakePiecesOnChessBoardDAO implements PiecesOnChessBoardDAO { private final Set pieces = new HashSet<>(); @Override - public boolean save(Piece piece) { + public boolean save(Piece piece, Connection connection) { return pieces.add(piece); } @Override - public boolean saveAll(List pieces) { + public boolean saveAll(List pieces, Connection connection) { for (Piece piece : pieces) { if (this.pieces.contains(piece)) { return false; } } for (Piece piece : pieces) { - save(piece); + save(piece, connection); } return true; } @Override - public List selectAll() { + public List selectAll(Connection connection) { return pieces.stream().toList(); } @Override - public boolean delete(Position targetPosition) { + public boolean delete(Position targetPosition, Connection connection) { return pieces.removeIf(piece -> piece.isOn(targetPosition)); } @Override - public void deleteAll() { + public void deleteAll(Connection connection) { pieces.clear(); } } diff --git a/src/test/java/chess/dao/FakeTurnDAO.java b/src/test/java/chess/dao/FakeTurnDAO.java index fb1d50148e6..11e4f56c265 100644 --- a/src/test/java/chess/dao/FakeTurnDAO.java +++ b/src/test/java/chess/dao/FakeTurnDAO.java @@ -1,18 +1,19 @@ package chess.dao; import chess.domain.piece.Team; +import java.sql.Connection; import java.util.Optional; public class FakeTurnDAO implements TurnDAO { private Team team; @Override - public Optional select() { + public Optional select(Connection connection) { return Optional.ofNullable(team); } @Override - public boolean save(Team team) { + public boolean save(Team team, Connection connection) { if (this.team == null) { this.team = team; return true; @@ -21,7 +22,7 @@ public boolean save(Team team) { } @Override - public boolean update(Team targetTeam, Team updatedTeam) { + public boolean update(Team targetTeam, Team updatedTeam, Connection connection) { if (targetTeam.equals(team)) { team = updatedTeam; return true; @@ -30,7 +31,7 @@ public boolean update(Team targetTeam, Team updatedTeam) { } @Override - public void delete() { + public void delete(Connection connection) { team = null; } } From 6e32f42e768a5b5cb59cf27309fd7623d508a0e3 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Sat, 30 Mar 2024 22:56:10 +0900 Subject: [PATCH 35/45] =?UTF-8?q?!refactor:=20TurnDAO=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 트랜잭션 적용하면서 해당 로직의 필요성이 없어졌다. --- README.md | 2 +- src/main/java/chess/dao/TurnDAOForMysql.java | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dc481d123a6..c1dcec1e4ba 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ CREATE TABLE `pieces_on_board` ( ### DB 관련 - [x] 트랜잭션 적용 -- [ ] TurnDAO에서 비즈니스 로직 상위로 이동 +- [x] TurnDAO에서 비즈니스 로직 상위로 이동 - [ ] DAO에 boolean을 반환하는 메서드 추가 - [ ] 구체적인 예외를 던지도록 수정 - [ ] DAO 테스트 추가 diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index 29db2ace19d..3ef6c85e80d 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -29,10 +29,7 @@ public Optional select(Connection connection) { public boolean save(Team team, Connection connection) { try { PreparedStatement preparedStatement = connection.prepareStatement( - "INSERT INTO game (current_team_name) " - + "SELECT ? " - + "FROM dual " - + "WHERE NOT EXISTS (SELECT * FROM game)"); + "INSERT INTO game (current_team_name) values ( ? )"); preparedStatement.setString(1, team.name()); return preparedStatement.executeUpdate() == 1; } catch (SQLException e) { From b74ed21e0ee4cdb1cc0963bc68ff1ebcdd3d22c7 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Sat, 30 Mar 2024 23:09:48 +0900 Subject: [PATCH 36/45] =?UTF-8?q?fix:=20DB=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D=20=EC=8B=9C=20=EA=B5=AC?= =?UTF-8?q?=EC=B2=B4=EC=A0=81=EC=9D=B8=20=EC=98=88=EC=99=B8=EB=A5=BC=20?= =?UTF-8?q?=EB=8D=98=EC=A7=80=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/chess/dao/ChessPersistence.java | 9 ++++++--- src/main/java/chess/dao/exception/DBException.java | 7 +++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 src/main/java/chess/dao/exception/DBException.java diff --git a/README.md b/README.md index c1dcec1e4ba..745a1941f6f 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ CREATE TABLE `pieces_on_board` ( - [x] 트랜잭션 적용 - [x] TurnDAO에서 비즈니스 로직 상위로 이동 - [ ] DAO에 boolean을 반환하는 메서드 추가 -- [ ] 구체적인 예외를 던지도록 수정 +- [x] 구체적인 예외를 던지도록 수정 - [ ] DAO 테스트 추가 - [ ] 킹이 잡힌 경우 데이터를 초기화하도록 수정 - [ ] 폰이 데이터베이스에서 로드된 뒤에 폰이 2칸 움직일 수 있는 버그 수정 diff --git a/src/main/java/chess/dao/ChessPersistence.java b/src/main/java/chess/dao/ChessPersistence.java index 6765050073e..c80c896745a 100644 --- a/src/main/java/chess/dao/ChessPersistence.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -1,5 +1,6 @@ package chess.dao; +import chess.dao.exception.DBException; import chess.domain.Position; import chess.domain.game.ChessGame; import chess.domain.game.command.MoveCommand; @@ -44,7 +45,7 @@ private void startTransaction(Connection connection) { try { connection.setAutoCommit(false); } catch (SQLException e) { - throw new RuntimeException(e); + throw new DBException("DB 접근에 오류가 발생했습니다.", e); } } @@ -60,8 +61,9 @@ public boolean isSaveDataExist() { private void commitTransaction(Connection connection) { try { connection.commit(); + connection.setAutoCommit(true); } catch (SQLException e) { - throw new RuntimeException(e); + throw new DBException("DB 접근에 오류가 발생했습니다.", e); } } @@ -98,6 +100,7 @@ public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { private Piece findMovedPiece(ChessGame chessGame, Position to) { return chessGame.getPiecesOnBoard().stream() .filter(piece -> piece.isOn(to)) - .findFirst().orElseThrow(); + .findFirst() + .orElseThrow(() -> new IllegalStateException("움직인 말이 없습니다.", null)); } } diff --git a/src/main/java/chess/dao/exception/DBException.java b/src/main/java/chess/dao/exception/DBException.java new file mode 100644 index 00000000000..c6e90521515 --- /dev/null +++ b/src/main/java/chess/dao/exception/DBException.java @@ -0,0 +1,7 @@ +package chess.dao.exception; + +public class DBException extends RuntimeException { + public DBException(String message, Throwable cause) { + super(message, cause); + } +} From 902fb55e0c46c82a6c8217d1803f46b1f9409e25 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 14:40:56 +0900 Subject: [PATCH 37/45] =?UTF-8?q?refactor:=20DAO=EC=97=90=20boolean?= =?UTF-8?q?=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/chess/dao/ChessPersistence.java | 22 +++++--- .../java/chess/dao/PiecesOnChessBoardDAO.java | 3 +- .../dao/PiecesOnChessBoardDAOForMysql.java | 56 +++++++++++-------- src/main/java/chess/dao/TurnDAO.java | 2 + src/main/java/chess/dao/TurnDAOForMysql.java | 12 ++++ .../chess/dao/FakePiecesOnChessBoardDAO.java | 5 ++ src/test/java/chess/dao/FakeTurnDAO.java | 5 ++ 8 files changed, 75 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 745a1941f6f..c762c502776 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ CREATE TABLE `pieces_on_board` ( - [x] 트랜잭션 적용 - [x] TurnDAO에서 비즈니스 로직 상위로 이동 -- [ ] DAO에 boolean을 반환하는 메서드 추가 +- [x] DAO에 boolean을 반환하는 메서드 추가 - [x] 구체적인 예외를 던지도록 수정 - [ ] DAO 테스트 추가 - [ ] 킹이 잡힌 경우 데이터를 초기화하도록 수정 diff --git a/src/main/java/chess/dao/ChessPersistence.java b/src/main/java/chess/dao/ChessPersistence.java index c80c896745a..cefbcc5292d 100644 --- a/src/main/java/chess/dao/ChessPersistence.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -9,7 +9,6 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; -import java.util.Optional; public class ChessPersistence { private final PiecesOnChessBoardDAO piecesOnChessBoardDAO; @@ -32,7 +31,7 @@ public ChessGame loadChessGame() { startTransaction(connection); if (isSaveDataExist()) { List pieces = piecesOnChessBoardDAO.selectAll(connection); - Team currentTeam = turnDAO.select(connection).orElseThrow(); + Team currentTeam = turnDAO.select(connection).get(); return new ChessGame(pieces, currentTeam); } piecesOnChessBoardDAO.deleteAll(connection); @@ -52,10 +51,10 @@ private void startTransaction(Connection connection) { public boolean isSaveDataExist() { Connection connection = dbConnectionCache.getConnection(); startTransaction(connection); - Optional selected = turnDAO.select(connection); - List pieces = piecesOnChessBoardDAO.selectAll(connection); + boolean turnNotEmpty = turnDAO.isNotEmpty(connection); + boolean piecesNotEmpty = piecesOnChessBoardDAO.isNotEmpty(connection); commitTransaction(connection); - return selected.isPresent() && !pieces.isEmpty(); + return turnNotEmpty && piecesNotEmpty; } private void commitTransaction(Connection connection) { @@ -71,7 +70,7 @@ public boolean saveChessGame(ChessGame chessGame) { Connection connection = dbConnectionCache.getConnection(); List piecesOnBoard = chessGame.getPiecesOnBoard(); startTransaction(connection); - if (!piecesOnChessBoardDAO.selectAll(connection).isEmpty() && turnDAO.select(connection).isPresent()) { + if (canNotSave(connection)) { return false; } boolean saveAllPiecesSuccess = piecesOnChessBoardDAO.saveAll(piecesOnBoard, connection); @@ -81,6 +80,12 @@ public boolean saveChessGame(ChessGame chessGame) { return saveAllPiecesSuccess && saveTurnSuccess; } + private boolean canNotSave(Connection connection) { + boolean piecesNotEmpty = piecesOnChessBoardDAO.isNotEmpty(connection); + boolean turnNotEmpty = turnDAO.isNotEmpty(connection); + return piecesNotEmpty && turnNotEmpty; + } + public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { Connection connection = dbConnectionCache.getConnection(); List positions = moveCommand.getOptions(); @@ -91,10 +96,11 @@ public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { boolean deleteToSuccess = piecesOnChessBoardDAO.delete(to, connection); Piece movedPiece = findMovedPiece(chessGame, to); boolean saveMovedPieceSuccess = piecesOnChessBoardDAO.save(movedPiece, connection); - Team team = turnDAO.select(connection).orElseThrow(); + Team team = turnDAO.select(connection) + .orElseThrow(() -> new DBException("데이터가 잘못되었습니다.", null)); boolean updateTurnSuccess = turnDAO.update(team, team.otherTeam(), connection); commitTransaction(connection); - return !deleteFromSuccess && deleteToSuccess && saveMovedPieceSuccess && updateTurnSuccess; + return deleteFromSuccess && deleteToSuccess && saveMovedPieceSuccess && updateTurnSuccess; } private Piece findMovedPiece(ChessGame chessGame, Position to) { diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java index d9a430f6102..571dbadbb0f 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAO.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAO.java @@ -12,8 +12,9 @@ public interface PiecesOnChessBoardDAO { List selectAll(Connection connection); + boolean isNotEmpty(Connection connection); + boolean delete(Position targetPosition, Connection connection); void deleteAll(Connection connection); - } diff --git a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java index 0ef771d5523..08e2fc3d092 100644 --- a/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java +++ b/src/main/java/chess/dao/PiecesOnChessBoardDAOForMysql.java @@ -59,6 +59,40 @@ public List selectAll(Connection connection) { } } + @Override + public boolean isNotEmpty(Connection connection) { + try { + PreparedStatement preparedStatement = connection.prepareStatement( + "select 1 from pieces_on_board where exists(select 1 from pieces_on_board) limit 1"); + ResultSet resultSet = preparedStatement.executeQuery(); + return resultSet.next(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean delete(Position targetPosition, Connection connection) { + try { + PreparedStatement preparedStatement = connection.prepareStatement( + "delete from pieces_on_board where position_name = ?"); + preparedStatement.setString(1, targetPosition.name()); + return preparedStatement.executeUpdate() == 1; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public void deleteAll(Connection connection) { + try { + PreparedStatement preparedStatement = connection.prepareStatement("delete from pieces_on_board"); + preparedStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + private List parsingResultSet(ResultSet resultSet) throws SQLException { List selected = new ArrayList<>(); while (resultSet.next()) { @@ -85,28 +119,6 @@ private Piece mapToPiece(PieceType pieceType, Team team, Position position) { }; } - @Override - public boolean delete(Position targetPosition, Connection connection) { - try { - PreparedStatement preparedStatement = connection.prepareStatement( - "delete from pieces_on_board where position_name = ?"); - preparedStatement.setString(1, targetPosition.name()); - return preparedStatement.executeUpdate() == 1; - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - @Override - public void deleteAll(Connection connection) { - try { - PreparedStatement preparedStatement = connection.prepareStatement("delete from pieces_on_board"); - preparedStatement.executeUpdate(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - private static void setPieceToPreparedStatement(List pieces, PreparedStatement preparedStatement) throws SQLException { for (int index = 0; index < pieces.size(); index++) { diff --git a/src/main/java/chess/dao/TurnDAO.java b/src/main/java/chess/dao/TurnDAO.java index 8ab79437c82..5d945a990c1 100644 --- a/src/main/java/chess/dao/TurnDAO.java +++ b/src/main/java/chess/dao/TurnDAO.java @@ -7,6 +7,8 @@ public interface TurnDAO { Optional select(Connection connection); + boolean isNotEmpty(Connection connection); + boolean save(Team team, Connection connection); boolean update(Team targetTeam, Team updatedTeam, Connection connection); diff --git a/src/main/java/chess/dao/TurnDAOForMysql.java b/src/main/java/chess/dao/TurnDAOForMysql.java index 3ef6c85e80d..756ae84f629 100644 --- a/src/main/java/chess/dao/TurnDAOForMysql.java +++ b/src/main/java/chess/dao/TurnDAOForMysql.java @@ -25,6 +25,18 @@ public Optional select(Connection connection) { } } + @Override + public boolean isNotEmpty(Connection connection) { + try { + PreparedStatement preparedStatement = connection.prepareStatement( + "select 1 from game where exists(select 1 from game) limit 1"); + ResultSet resultSet = preparedStatement.executeQuery(); + return resultSet.next(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + @Override public boolean save(Team team, Connection connection) { try { diff --git a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java index 2178523c8a7..3ce3b91a56f 100644 --- a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java +++ b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java @@ -33,6 +33,11 @@ public List selectAll(Connection connection) { return pieces.stream().toList(); } + @Override + public boolean isNotEmpty(Connection connection) { + return !selectAll(connection).isEmpty(); + } + @Override public boolean delete(Position targetPosition, Connection connection) { return pieces.removeIf(piece -> piece.isOn(targetPosition)); diff --git a/src/test/java/chess/dao/FakeTurnDAO.java b/src/test/java/chess/dao/FakeTurnDAO.java index 11e4f56c265..ae550f2a641 100644 --- a/src/test/java/chess/dao/FakeTurnDAO.java +++ b/src/test/java/chess/dao/FakeTurnDAO.java @@ -12,6 +12,11 @@ public Optional select(Connection connection) { return Optional.ofNullable(team); } + @Override + public boolean isNotEmpty(Connection connection) { + return select(connection).isPresent(); + } + @Override public boolean save(Team team, Connection connection) { if (this.team == null) { From 91307313eaa3b74174370e4a40bdfaa3d3934b44 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 14:44:59 +0900 Subject: [PATCH 38/45] =?UTF-8?q?docs:=20=EC=B4=88=EA=B8=B0=20sql=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 --- chess_2024-04-01.sql | 195 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 chess_2024-04-01.sql diff --git a/chess_2024-04-01.sql b/chess_2024-04-01.sql new file mode 100644 index 00000000000..956d763bb86 --- /dev/null +++ b/chess_2024-04-01.sql @@ -0,0 +1,195 @@ +# ************************************************************ +# Sequel Ace SQL dump +# Version 20062 +# +# https://sequel-ace.com/ +# https://github.com/Sequel-Ace/Sequel-Ace +# +# Host: localhost (MySQL 8.0.28) +# Database: chess +# Generation Time: 2024-04-01 05:43:10 +0000 +# ************************************************************ + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +SET NAMES utf8mb4; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE='NO_AUTO_VALUE_ON_ZERO', SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + + +# Dump of table game +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `game`; + +CREATE TABLE `game` ( + `current_team_name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + KEY `fj_team_game` (`current_team_name`), + CONSTRAINT `fj_team_game` FOREIGN KEY (`current_team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + + + +# Dump of table piece +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `piece`; + +CREATE TABLE `piece` ( + `piece_type` varchar(16) NOT NULL, + PRIMARY KEY (`piece_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +LOCK TABLES `piece` WRITE; +/*!40000 ALTER TABLE `piece` DISABLE KEYS */; + +INSERT INTO `piece` (`piece_type`) +VALUES + ('BISHOP'), + ('KING'), + ('KNIGHT'), + ('PAWN'), + ('QUEEN'), + ('ROOK'); + +/*!40000 ALTER TABLE `piece` ENABLE KEYS */; +UNLOCK TABLES; + + +# Dump of table pieces_on_board +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `pieces_on_board`; + +CREATE TABLE `pieces_on_board` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `piece_type` varchar(16) NOT NULL, + `team_name` varchar(16) NOT NULL, + `position_name` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + PRIMARY KEY (`id`), + KEY `fk-piece-pieces_on_board` (`piece_type`), + KEY `fk-position-pieces_on_board` (`position_name`), + KEY `fk-team-pieces_on_board` (`team_name`), + CONSTRAINT `fk-piece-pieces_on_board` FOREIGN KEY (`piece_type`) REFERENCES `piece` (`piece_type`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `fk-position-pieces_on_board` FOREIGN KEY (`position_name`) REFERENCES `position` (`name`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `fk-team-pieces_on_board` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + + + +# Dump of table position +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `position`; + +CREATE TABLE `position` ( + `name` char(2) NOT NULL, + PRIMARY KEY (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +LOCK TABLES `position` WRITE; +/*!40000 ALTER TABLE `position` DISABLE KEYS */; + +INSERT INTO `position` (`name`) +VALUES + ('A1'), + ('A2'), + ('A3'), + ('A4'), + ('A5'), + ('A6'), + ('A7'), + ('A8'), + ('B1'), + ('B2'), + ('B3'), + ('B4'), + ('B5'), + ('B6'), + ('B7'), + ('B8'), + ('C1'), + ('C2'), + ('C3'), + ('C4'), + ('C5'), + ('C6'), + ('C7'), + ('C8'), + ('D1'), + ('D2'), + ('D3'), + ('D4'), + ('D5'), + ('D6'), + ('D7'), + ('D8'), + ('E1'), + ('E2'), + ('E3'), + ('E4'), + ('E5'), + ('E6'), + ('E7'), + ('E8'), + ('F1'), + ('F2'), + ('F3'), + ('F4'), + ('F5'), + ('F6'), + ('F7'), + ('F8'), + ('G1'), + ('G2'), + ('G3'), + ('G4'), + ('G5'), + ('G6'), + ('G7'), + ('G8'), + ('H1'), + ('H2'), + ('H3'), + ('H4'), + ('H5'), + ('H6'), + ('H7'), + ('H8'); + +/*!40000 ALTER TABLE `position` ENABLE KEYS */; +UNLOCK TABLES; + + +# Dump of table team +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `team`; + +CREATE TABLE `team` ( + `team_name` varchar(16) NOT NULL, + PRIMARY KEY (`team_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +LOCK TABLES `team` WRITE; +/*!40000 ALTER TABLE `team` DISABLE KEYS */; + +INSERT INTO `team` (`team_name`) +VALUES + ('black'), + ('white'); + +/*!40000 ALTER TABLE `team` ENABLE KEYS */; +UNLOCK TABLES; + + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; From 2e61cc3ac18158a69cc944b0be2756bacc36bc9b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 14:52:02 +0900 Subject: [PATCH 39/45] =?UTF-8?q?feat:=20end=20=EC=BB=A4=EB=A9=98=EB=93=9C?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=ED=95=98=EB=A9=B0=20=EC=A2=85=EB=A3=8C=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EA=B2=83=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/chess/Application.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 9168d12fc44..e68c42358d6 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -67,12 +67,19 @@ private static void playChess(ChessGame chessGame) { } while (!isEndCommand(endOrMoveOrStatus) && !pieceMoveResult.isEnd()); } - private static PieceMoveResult playGameOrPrintStatus(Command moveOrStatus, ChessGame chessGame) { - if (moveOrStatus.equals(StatusCommand.STATUS_COMMAND)) { + private static PieceMoveResult playGameOrPrintStatus(Command endOrMoveOrStatus, ChessGame chessGame) { + if (isStatusCommand(endOrMoveOrStatus)) { printStatus(chessGame); return FAILURE; } - return playGame((MoveCommand) moveOrStatus, chessGame); + if (isEndCommand(endOrMoveOrStatus)) { + return FAILURE; + } + return playGame((MoveCommand) endOrMoveOrStatus, chessGame); + } + + private static boolean isStatusCommand(Command endOrMoveOrStatus) { + return endOrMoveOrStatus.equals(StatusCommand.STATUS_COMMAND); } private static void printStatus(ChessGame chessGame) { From 83c7b625835b55a79bcb9c23a0fda66886162422 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 16:16:09 +0900 Subject: [PATCH 40/45] =?UTF-8?q?test:=20DAO=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../PiecesOnChessBoardDAOForMysqlTest.java | 118 ++++++++++++++++++ .../java/chess/dao/TurnDAOForMysqlTest.java | 103 +++++++++++++++ 3 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java create mode 100644 src/test/java/chess/dao/TurnDAOForMysqlTest.java diff --git a/README.md b/README.md index c762c502776..b289f5549ed 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ CREATE TABLE `pieces_on_board` ( - [x] TurnDAO에서 비즈니스 로직 상위로 이동 - [x] DAO에 boolean을 반환하는 메서드 추가 - [x] 구체적인 예외를 던지도록 수정 -- [ ] DAO 테스트 추가 +- [x] DAO 테스트 추가 - [ ] 킹이 잡힌 경우 데이터를 초기화하도록 수정 - [ ] 폰이 데이터베이스에서 로드된 뒤에 폰이 2칸 움직일 수 있는 버그 수정 diff --git a/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java b/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java new file mode 100644 index 00000000000..4341627daab --- /dev/null +++ b/src/test/java/chess/dao/PiecesOnChessBoardDAOForMysqlTest.java @@ -0,0 +1,118 @@ +package chess.dao; + +import static chess.domain.Position.A2; +import static chess.domain.Position.B2; +import static chess.domain.piece.Team.WHITE; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.dao.exception.DBException; +import chess.domain.piece.Pawn; +import chess.domain.piece.Piece; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; +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 PiecesOnChessBoardDAOForMysqlTest { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess2?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + private static final DBConnectionCache DB_CONNECTION_CACHE = new MysqlDBConnectionCache(DB_URL, DB_USER_NAME, + DB_USER_PASSWORD); + private static final PiecesOnChessBoardDAOForMysql DAO_FOR_MYSQL = new PiecesOnChessBoardDAOForMysql(); + + @BeforeEach + void setUp() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + try { + connection.setAutoCommit(false); + } catch (SQLException e) { + throw new DBException("DB 접속 오류", e); + } + } + + @AfterEach + void tearDown() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + try { + connection.rollback(); + connection.setAutoCommit(true); + } catch (SQLException e) { + throw new DBException("DB 접속 오류", e); + } + } + + @Test + @DisplayName("체스 보드 위의 기물 정보가 잘 저장되는지 검증") + void save() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + boolean saveResult = DAO_FOR_MYSQL.save(new Pawn(A2, WHITE), connection); + Assertions.assertThat(saveResult) + .isTrue(); + } + + @Test + @DisplayName("체스 보드 위의 여러 기물 정보가 잘 저장되는지 검증") + void saveAll() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + boolean saveResult = DAO_FOR_MYSQL.saveAll(List.of(new Pawn(A2, WHITE), new Pawn(B2, WHITE)), connection); + Assertions.assertThat(saveResult) + .isTrue(); + } + + @Test + @DisplayName("저장된 체스 보드 위의 여러 기물 정보를 잘 불러오는지 검증") + void selectAll() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + List pieces = List.of(new Pawn(A2, WHITE), new Pawn(B2, WHITE)); + DAO_FOR_MYSQL.saveAll(pieces, connection); + + List selected = DAO_FOR_MYSQL.selectAll(connection); + + Assertions.assertThat(selected) + .containsExactlyInAnyOrderElementsOf(pieces); + } + + @Test + @DisplayName("체스 보드 위에 말이 있는지 잘 판단하는지 검증") + void isNotEmpty() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + boolean notEmptyWhenBoardIsEmpty = DAO_FOR_MYSQL.isNotEmpty(connection); + DAO_FOR_MYSQL.save(new Pawn(A2, WHITE), connection); + boolean notEmptyWhenBoardIsNotEmpty = DAO_FOR_MYSQL.isNotEmpty(connection); + assertAll( + () -> Assertions.assertThat(notEmptyWhenBoardIsEmpty).isFalse(), + () -> Assertions.assertThat(notEmptyWhenBoardIsNotEmpty).isTrue() + ); + } + + @Test + @DisplayName("체스 보드 위의 말을 잘 지우는지 검증") + void delete() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + DAO_FOR_MYSQL.save(new Pawn(A2, WHITE), connection); + + boolean deleteResult = DAO_FOR_MYSQL.delete(A2, connection); + + Assertions.assertThat(deleteResult) + .isTrue(); + } + + @Test + @DisplayName("체스 보드 위의 모든 말을 잘 지우는지 검증") + void deleteAll() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + List pieces = List.of(new Pawn(A2, WHITE), new Pawn(B2, WHITE)); + DAO_FOR_MYSQL.saveAll(pieces, connection); + + DAO_FOR_MYSQL.deleteAll(connection); + + List selected = DAO_FOR_MYSQL.selectAll(connection); + Assertions.assertThat(selected) + .isEmpty(); + } +} diff --git a/src/test/java/chess/dao/TurnDAOForMysqlTest.java b/src/test/java/chess/dao/TurnDAOForMysqlTest.java new file mode 100644 index 00000000000..2f1e34acbbd --- /dev/null +++ b/src/test/java/chess/dao/TurnDAOForMysqlTest.java @@ -0,0 +1,103 @@ +package chess.dao; + +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.dao.exception.DBException; +import chess.domain.piece.Team; +import java.sql.Connection; +import java.sql.SQLException; +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 TurnDAOForMysqlTest { + private static final String DB_URL = "jdbc:mysql://localhost:13306/chess2?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String DB_USER_NAME = "user"; + private static final String DB_USER_PASSWORD = "password"; + private static final DBConnectionCache DB_CONNECTION_CACHE = new MysqlDBConnectionCache(DB_URL, DB_USER_NAME, + DB_USER_PASSWORD); + private static final TurnDAOForMysql TURN_DAO_FOR_MYSQL = new TurnDAOForMysql(); + + @BeforeEach + void setUp() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + try { + connection.setAutoCommit(false); + } catch (SQLException e) { + throw new DBException("DB 접속 오류", e); + } + } + + @AfterEach + void tearDown() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + try { + connection.rollback(); + connection.setAutoCommit(true); + } catch (SQLException e) { + throw new DBException("DB 접속 오류", e); + } + } + + @Test + @DisplayName("현재 기물을 움직일 차례를 잘 불러오는지 검증") + void select() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + TURN_DAO_FOR_MYSQL.save(WHITE, connection); + + Team team = TURN_DAO_FOR_MYSQL.select(connection).get(); + Assertions.assertThat(team) + .isEqualTo(WHITE); + } + + @Test + @DisplayName("현재 기물을 움직일 차례가 저징되어있는지 잘 판단하는지 검증") + void isNotEmpty() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + boolean notEmptyWhenTurnEmpty = TURN_DAO_FOR_MYSQL.isNotEmpty(connection); + TURN_DAO_FOR_MYSQL.save(WHITE, connection); + boolean notEmptyWhenTurnNotEmpty = TURN_DAO_FOR_MYSQL.isNotEmpty(connection); + + assertAll( + () -> Assertions.assertThat(notEmptyWhenTurnEmpty).isFalse(), + () -> Assertions.assertThat(notEmptyWhenTurnNotEmpty).isTrue() + ); + } + + @Test + @DisplayName("현재 기물을 움직일 차례를 잘 저장하는지 검증") + void save() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + boolean saveResult = TURN_DAO_FOR_MYSQL.save(WHITE, connection); + + Assertions.assertThat(saveResult) + .isTrue(); + } + + @Test + @DisplayName("현재 기물을 움직일 차례를 잘 수정하는지 검증") + void update() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + TURN_DAO_FOR_MYSQL.save(WHITE, connection); + + boolean updateResult = TURN_DAO_FOR_MYSQL.update(WHITE, BLACK, connection); + + Assertions.assertThat(updateResult) + .isTrue(); + } + + @Test + @DisplayName("현재 기물을 움직일 차례를 잘 지우는지 검증") + void delete() { + Connection connection = DB_CONNECTION_CACHE.getConnection(); + TURN_DAO_FOR_MYSQL.delete(connection); + + boolean notEmpty = TURN_DAO_FOR_MYSQL.isNotEmpty(connection); + Assertions.assertThat(notEmpty) + .isFalse(); + } +} From 1fa4710ab88aff94e4119ec6043f889c0ef923a6 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 16:21:08 +0900 Subject: [PATCH 41/45] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/dao/ChessPersistence.java | 4 ++-- .../chess/dao/FakePiecesOnChessBoardDAO.java | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/chess/dao/ChessPersistence.java b/src/main/java/chess/dao/ChessPersistence.java index cefbcc5292d..6f7c49ddff7 100644 --- a/src/main/java/chess/dao/ChessPersistence.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -93,14 +93,14 @@ public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { Position to = positions.get(1); startTransaction(connection); boolean deleteFromSuccess = piecesOnChessBoardDAO.delete(from, connection); - boolean deleteToSuccess = piecesOnChessBoardDAO.delete(to, connection); + piecesOnChessBoardDAO.delete(to, connection); Piece movedPiece = findMovedPiece(chessGame, to); boolean saveMovedPieceSuccess = piecesOnChessBoardDAO.save(movedPiece, connection); Team team = turnDAO.select(connection) .orElseThrow(() -> new DBException("데이터가 잘못되었습니다.", null)); boolean updateTurnSuccess = turnDAO.update(team, team.otherTeam(), connection); commitTransaction(connection); - return deleteFromSuccess && deleteToSuccess && saveMovedPieceSuccess && updateTurnSuccess; + return deleteFromSuccess && saveMovedPieceSuccess && updateTurnSuccess; } private Piece findMovedPiece(ChessGame chessGame, Position to) { diff --git a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java index 3ce3b91a56f..14f3adfda73 100644 --- a/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java +++ b/src/test/java/chess/dao/FakePiecesOnChessBoardDAO.java @@ -1,7 +1,14 @@ package chess.dao; import chess.domain.Position; +import chess.domain.piece.Bishop; +import chess.domain.piece.King; +import chess.domain.piece.Knight; +import chess.domain.piece.Pawn; import chess.domain.piece.Piece; +import chess.domain.piece.Queen; +import chess.domain.piece.Rook; +import chess.domain.piece.Team; import java.sql.Connection; import java.util.HashSet; import java.util.List; @@ -12,7 +19,22 @@ public class FakePiecesOnChessBoardDAO implements PiecesOnChessBoardDAO { @Override public boolean save(Piece piece, Connection connection) { - return pieces.add(piece); + return pieces.add(copy(piece)); + } + + private Piece copy(Piece piece) { + int row = piece.getRow(); + int column = piece.getColumn(); + Position position = Position.getInstance(row, column); + Team team = piece.getTeam(); + return switch (piece.getPieceType()) { + case ROOK -> new Rook(position, team); + case BISHOP -> new Bishop(position, team); + case KING -> new King(position, team); + case PAWN -> new Pawn(position, team); + case KNIGHT -> new Knight(position, team); + case QUEEN -> new Queen(position, team); + }; } @Override From 831f54b110287224670b8881537493ce5851d9cd Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 16:33:55 +0900 Subject: [PATCH 42/45] =?UTF-8?q?fix:=20=ED=82=B9=EC=9D=B4=20=EC=9E=A1?= =?UTF-8?q?=ED=9E=8C=20=EA=B2=BD=EC=9A=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=A5=BC=20=EC=B4=88=EA=B8=B0=ED=99=94=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/chess/Application.java | 5 ++++- src/main/java/chess/dao/ChessPersistence.java | 13 ++++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b289f5549ed..aab3c27f6c8 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ CREATE TABLE `pieces_on_board` ( - [x] DAO에 boolean을 반환하는 메서드 추가 - [x] 구체적인 예외를 던지도록 수정 - [x] DAO 테스트 추가 -- [ ] 킹이 잡힌 경우 데이터를 초기화하도록 수정 +- [x] 킹이 잡힌 경우 데이터를 초기화하도록 수정 - [ ] 폰이 데이터베이스에서 로드된 뒤에 폰이 2칸 움직일 수 있는 버그 수정 ### 도메인 로직 관련 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index e68c42358d6..fa71945f8a1 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -29,10 +29,10 @@ public static void main(String[] args) { if (isEndCommand(startOrEnd)) { return; } + ChessGame chessGame = CHESS_PERSISTENCE_SERVICE.loadChessGame(); if (!CHESS_PERSISTENCE_SERVICE.isSaveDataExist()) { CHESS_PERSISTENCE_SERVICE.saveChessGame(new ChessGame()); } - ChessGame chessGame = CHESS_PERSISTENCE_SERVICE.loadChessGame(); printPiecesOnChessBoard(chessGame); playChess(chessGame); @@ -95,6 +95,9 @@ private static PieceMoveResult playGame(MoveCommand moveCommand, ChessGame chess if (!moveResult.equals(FAILURE)) { CHESS_PERSISTENCE_SERVICE.updateChessGame(chessGame, moveCommand); } + if (moveResult.isEnd()) { + CHESS_PERSISTENCE_SERVICE.deleteAll(); + } printPiecesOnChessBoard(chessGame); printReInputGuideIfNeed(moveResult); printWinnerIfNeed(moveResult); diff --git a/src/main/java/chess/dao/ChessPersistence.java b/src/main/java/chess/dao/ChessPersistence.java index 6f7c49ddff7..7f82339e7a5 100644 --- a/src/main/java/chess/dao/ChessPersistence.java +++ b/src/main/java/chess/dao/ChessPersistence.java @@ -32,6 +32,7 @@ public ChessGame loadChessGame() { if (isSaveDataExist()) { List pieces = piecesOnChessBoardDAO.selectAll(connection); Team currentTeam = turnDAO.select(connection).get(); + commitTransaction(connection); return new ChessGame(pieces, currentTeam); } piecesOnChessBoardDAO.deleteAll(connection); @@ -50,10 +51,8 @@ private void startTransaction(Connection connection) { public boolean isSaveDataExist() { Connection connection = dbConnectionCache.getConnection(); - startTransaction(connection); boolean turnNotEmpty = turnDAO.isNotEmpty(connection); boolean piecesNotEmpty = piecesOnChessBoardDAO.isNotEmpty(connection); - commitTransaction(connection); return turnNotEmpty && piecesNotEmpty; } @@ -83,7 +82,7 @@ public boolean saveChessGame(ChessGame chessGame) { private boolean canNotSave(Connection connection) { boolean piecesNotEmpty = piecesOnChessBoardDAO.isNotEmpty(connection); boolean turnNotEmpty = turnDAO.isNotEmpty(connection); - return piecesNotEmpty && turnNotEmpty; + return piecesNotEmpty || turnNotEmpty; } public boolean updateChessGame(ChessGame chessGame, MoveCommand moveCommand) { @@ -109,4 +108,12 @@ private Piece findMovedPiece(ChessGame chessGame, Position to) { .findFirst() .orElseThrow(() -> new IllegalStateException("움직인 말이 없습니다.", null)); } + + public void deleteAll() { + Connection connection = dbConnectionCache.getConnection(); + startTransaction(connection); + piecesOnChessBoardDAO.deleteAll(connection); + turnDAO.delete(connection); + commitTransaction(connection); + } } From 5ac321e6a6f25ec4f4e18ab4c4725f8825701ae2 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 16:51:37 +0900 Subject: [PATCH 43/45] =?UTF-8?q?fix:=20=ED=8F=B0=EC=9D=B4=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4=EC=8A=A4=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EB=A1=9C=EB=93=9C=EB=90=9C=20=EB=92=A4=EC=97=90=20=ED=8F=B0?= =?UTF-8?q?=EC=9D=B4=202=EC=B9=B8=20=EC=9B=80=EC=A7=81=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/chess/domain/piece/Pawn.java | 62 ++++++++++++---------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index aab3c27f6c8..6421f8a12b9 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ CREATE TABLE `pieces_on_board` ( - [x] 구체적인 예외를 던지도록 수정 - [x] DAO 테스트 추가 - [x] 킹이 잡힌 경우 데이터를 초기화하도록 수정 -- [ ] 폰이 데이터베이스에서 로드된 뒤에 폰이 2칸 움직일 수 있는 버그 수정 +- [x] 폰이 데이터베이스에서 로드된 뒤에 폰이 2칸 움직일 수 있는 버그 수정 ### 도메인 로직 관련 diff --git a/src/main/java/chess/domain/piece/Pawn.java b/src/main/java/chess/domain/piece/Pawn.java index c4c9f927b24..2f3eecce9d7 100644 --- a/src/main/java/chess/domain/piece/Pawn.java +++ b/src/main/java/chess/domain/piece/Pawn.java @@ -1,17 +1,39 @@ package chess.domain.piece; +import static chess.domain.Position.A2; +import static chess.domain.Position.A7; +import static chess.domain.Position.B2; +import static chess.domain.Position.B7; +import static chess.domain.Position.C2; +import static chess.domain.Position.C7; +import static chess.domain.Position.D2; +import static chess.domain.Position.D7; +import static chess.domain.Position.E2; +import static chess.domain.Position.E7; +import static chess.domain.Position.F2; +import static chess.domain.Position.F7; +import static chess.domain.Position.G2; +import static chess.domain.Position.G7; +import static chess.domain.Position.H2; +import static chess.domain.Position.H7; +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; + import chess.domain.Position; import chess.domain.board.ChessBoard; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; public final class Pawn extends AbstractPiece { - - private final Position initialPosition; + private static final Map> MOVE_FORWARD_TWO_ABLE_POSITIONS = Map.of( + WHITE, Set.of(A2, B2, C2, D2, E2, F2, G2, H2), + BLACK, Set.of(A7, B7, C7, D7, E7, F7, G7, H7) + ); public Pawn(Position position, Team team) { super(position, team); - this.initialPosition = position; } @Override @@ -37,7 +59,7 @@ private boolean isMoveForward(Position targetPosition) { private int forwardDirection() { Team team = getTeam(); - if (team.equals(Team.WHITE)) { + if (team.equals(WHITE)) { return 1; } return -1; @@ -53,7 +75,7 @@ private boolean isMoveForwardTwo(Position targetPosition, ChessBoard chessBoard) List route = nowPosition.route(targetPosition); boolean rightDirection = nowPosition.rowDistance(targetPosition) == 2 * forwardDirection(); boolean sameColumn = nowPosition.isSameColumn(targetPosition); - boolean firstMove = nowPosition.equals(initialPosition); + boolean firstMove = isFirstMove(); boolean allPieceOnRouteIsEmpty = isAllPieceOnRouteIsEmpty(chessBoard, route); return rightDirection && sameColumn && firstMove && allPieceOnRouteIsEmpty; } @@ -64,6 +86,12 @@ private boolean isAllPieceOnRouteIsEmpty(ChessBoard chessBoard, List r .allMatch(Optional::isEmpty); } + private boolean isFirstMove() { + Team team = getTeam(); + Set positions = MOVE_FORWARD_TWO_ABLE_POSITIONS.get(team); + return positions.contains(getPosition()); + } + private boolean isMoveDiagonal(Position targetPosition) { Position nowPosition = getPosition(); int rowDistance = nowPosition.rowDistance(targetPosition); @@ -80,30 +108,6 @@ private boolean isOtherTeam(Position targetPosition, ChessBoard chessBoard) { .isPresent(); } - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (initialPosition != null ? initialPosition.hashCode() : 0); - return result; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.equals(o)) { - return false; - } - - Pawn pawn = (Pawn) o; - - return initialPosition == pawn.initialPosition; - } - @Override public PieceType getPieceType() { return PieceType.PAWN; From b307ff76cc9bfaf1f16d12fa9ff0d9213b5c180b Mon Sep 17 00:00:00 2001 From: robinjoon Date: Mon, 1 Apr 2024 16:56:56 +0900 Subject: [PATCH 44/45] =?UTF-8?q?refactor:=20=EC=A0=90=EC=88=98=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/chess/domain/board/ChessBoard.java | 1 - .../{game => board}/PointCalculator.java | 6 +- .../chess/domain/board/ChessBoardTest.java | 32 ---------- .../domain/board/PointCalculatorTest.java | 58 +++++++++++++++++++ 4 files changed, 61 insertions(+), 36 deletions(-) rename src/main/java/chess/domain/{game => board}/PointCalculator.java (92%) create mode 100644 src/test/java/chess/domain/board/PointCalculatorTest.java diff --git a/src/main/java/chess/domain/board/ChessBoard.java b/src/main/java/chess/domain/board/ChessBoard.java index 8b26cc85485..23bb5db7d3a 100644 --- a/src/main/java/chess/domain/board/ChessBoard.java +++ b/src/main/java/chess/domain/board/ChessBoard.java @@ -4,7 +4,6 @@ import static chess.domain.piece.Team.WHITE; import chess.domain.Position; -import chess.domain.game.PointCalculator; import chess.domain.piece.Piece; import chess.domain.piece.PieceMoveResult; import chess.domain.piece.PieceType; diff --git a/src/main/java/chess/domain/game/PointCalculator.java b/src/main/java/chess/domain/board/PointCalculator.java similarity index 92% rename from src/main/java/chess/domain/game/PointCalculator.java rename to src/main/java/chess/domain/board/PointCalculator.java index 0f65f939ed9..ce51cbaeda6 100644 --- a/src/main/java/chess/domain/game/PointCalculator.java +++ b/src/main/java/chess/domain/board/PointCalculator.java @@ -1,4 +1,4 @@ -package chess.domain.game; +package chess.domain.board; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; @@ -8,8 +8,8 @@ import java.util.Map; import java.util.stream.Collectors; -public class PointCalculator { - public static double calculatePoint(Team team, List piecesOnBoard) { +class PointCalculator { + static double calculatePoint(Team team, List piecesOnBoard) { piecesOnBoard = Collections.unmodifiableList(piecesOnBoard); double totalPoint = calculateWithOutSameColumnPawn(team, piecesOnBoard); Map> pawnsAtSameColumn = pawnGroupingByColumn(team, piecesOnBoard); diff --git a/src/test/java/chess/domain/board/ChessBoardTest.java b/src/test/java/chess/domain/board/ChessBoardTest.java index 1854abfb7b4..36f74288a74 100644 --- a/src/test/java/chess/domain/board/ChessBoardTest.java +++ b/src/test/java/chess/domain/board/ChessBoardTest.java @@ -1,10 +1,8 @@ package chess.domain.board; import static chess.domain.Position.A1; -import static chess.domain.Position.A2; import static chess.domain.Position.A3; import static chess.domain.Position.A4; -import static chess.domain.Position.A5; import static chess.domain.Position.A6; import static chess.domain.Position.A8; import static chess.domain.Position.B1; @@ -30,7 +28,6 @@ import static chess.domain.piece.PieceMoveResult.SUCCESS; import static chess.domain.piece.Team.BLACK; import static chess.domain.piece.Team.WHITE; -import static org.junit.jupiter.api.Assertions.assertAll; import chess.domain.Position; import chess.domain.piece.Bishop; @@ -46,7 +43,6 @@ import java.util.Optional; import java.util.stream.Stream; import org.assertj.core.api.Assertions; -import org.assertj.core.data.Offset; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -170,32 +166,4 @@ void whichTeamWhenEmpty() { Assertions.assertThat(actual) .isEmpty(); } - - @Test - @DisplayName("각 팀의 점수가 잘 계산되는지 검증") - void calculatePoint() { - ChessBoard chessBoard = new ChessBoard(); - double whiteTeamPoint = chessBoard.calculatePoint(WHITE); - double blackTeamPoint = chessBoard.calculatePoint(BLACK); - Offset offset = Offset.offset(0.01); - assertAll( - () -> Assertions.assertThat(whiteTeamPoint).isCloseTo(38.0, offset), - () -> Assertions.assertThat(blackTeamPoint).isCloseTo(38.0, offset) - ); - } - - @Test - @DisplayName("같은 열의 폰이 포함된 각 팀의 점수가 잘 계산되는지 검증") - void calculatePointWithPawn() { - ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(A2, BLACK), - new Pawn(B2, BLACK), new Pawn(A3, BLACK), - new Pawn(A4, WHITE), new Pawn(A5, WHITE), new Pawn(A6, WHITE)); - double whiteTeamPoint = chessBoard.calculatePoint(WHITE); - double blackTeamPoint = chessBoard.calculatePoint(BLACK); - Offset offset = Offset.offset(0.01); - assertAll( - () -> Assertions.assertThat(blackTeamPoint).isCloseTo(2.0, offset), - () -> Assertions.assertThat(whiteTeamPoint).isCloseTo(1.5, offset) - ); - } } diff --git a/src/test/java/chess/domain/board/PointCalculatorTest.java b/src/test/java/chess/domain/board/PointCalculatorTest.java new file mode 100644 index 00000000000..ccf10763d90 --- /dev/null +++ b/src/test/java/chess/domain/board/PointCalculatorTest.java @@ -0,0 +1,58 @@ +package chess.domain.board; + +import static chess.domain.Position.A2; +import static chess.domain.Position.A3; +import static chess.domain.Position.A4; +import static chess.domain.Position.A5; +import static chess.domain.Position.A6; +import static chess.domain.Position.A8; +import static chess.domain.Position.B2; +import static chess.domain.Position.H1; +import static chess.domain.piece.Team.BLACK; +import static chess.domain.piece.Team.WHITE; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.piece.King; +import chess.domain.piece.Pawn; +import chess.domain.piece.Piece; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.assertj.core.data.Offset; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PointCalculatorTest { + @Test + @DisplayName("각 팀의 점수가 잘 계산되는지 검증") + void calculatePoint() { + ChessBoard chessBoard = new ChessBoard(); + List piecesOnBoard = chessBoard.getPiecesOnBoard(); + + double whiteTeamPoint = PointCalculator.calculatePoint(WHITE, piecesOnBoard); + double blackTeamPoint = PointCalculator.calculatePoint(WHITE, piecesOnBoard); + Offset offset = Offset.offset(0.01); + + assertAll( + () -> Assertions.assertThat(whiteTeamPoint).isCloseTo(38.0, offset), + () -> Assertions.assertThat(blackTeamPoint).isCloseTo(38.0, offset) + ); + } + + @Test + @DisplayName("같은 열의 폰이 포함된 각 팀의 점수가 잘 계산되는지 검증") + void calculatePointWithPawn() { + ChessBoard chessBoard = new ChessBoard(new King(A8, WHITE), new King(H1, BLACK), new Pawn(A2, BLACK), + new Pawn(B2, BLACK), new Pawn(A3, BLACK), + new Pawn(A4, WHITE), new Pawn(A5, WHITE), new Pawn(A6, WHITE)); + List piecesOnBoard = chessBoard.getPiecesOnBoard(); + + double whiteTeamPoint = PointCalculator.calculatePoint(WHITE, piecesOnBoard); + double blackTeamPoint = PointCalculator.calculatePoint(BLACK, piecesOnBoard); + Offset offset = Offset.offset(0.01); + + assertAll( + () -> Assertions.assertThat(blackTeamPoint).isCloseTo(2.0, offset), + () -> Assertions.assertThat(whiteTeamPoint).isCloseTo(1.5, offset) + ); + } +} From 143b63724709048e115a9dbea0348f6a208f0fe5 Mon Sep 17 00:00:00 2001 From: robinjoon Date: Tue, 2 Apr 2024 00:33:53 +0900 Subject: [PATCH 45/45] =?UTF-8?q?docs:=20docker-compose.yml=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 --- docker-compose.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000000..558a1d5a53f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.9" +services: + db: + image: mysql:8.0.28 + platform: linux/x86_64 + restart: always + ports: + - "13306:3306" + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: chess + MYSQL_USER: user + MYSQL_PASSWORD: password + TZ: Asia/Seoul + volumes: + - ./db/mysql/data:/var/lib/mysql + - ./db/mysql/config:/etc/mysql/conf.d + - ./db/mysql/init:/docker-entrypoint-initdb.d