From 5eec3982f724eb09ba1f448e0494c2090d05f2e9 Mon Sep 17 00:00:00 2001 From: Seokmyung Ham Date: Tue, 26 Mar 2024 01:10:00 +0900 Subject: [PATCH 01/18] =?UTF-8?q?[1,=202=EB=8B=A8=EA=B3=84=20-=20=EC=B2=B4?= =?UTF-8?q?=EC=8A=A4]=20=EC=9E=AC=EC=A6=88(=ED=95=A8=EC=84=9D=EB=AA=85)=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.=20(#703)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs : 기능 구현 목록 작성 * feat : Poistion 객체 생성 Co-authored-by: seokmyungham * feat : Unit 객체 생성 Co-authored-by: seokmyungham * feat : 각 기물에 대한 객체 생성 및 보드 초기화 Co-authored-by: seokmyungham * feat : 명령어를 입력 받고 초기화한 보드를 출력하는 기능 구현 Co-authored-by: seokmyungham * refactor : 전략 인터페이스를 도입하여 체스판 초기화 리팩터링 Co-authored-by: seokmyungham * fix : 행, 열 방향 수정 Co-authored-by: seokmyungham * feat(RookMoveStrategy) : 룩 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(BlackPawnMoveStrategy) : 블랙 폰 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(WhitePawnMoveStrategy) : 화이트 폰 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(BishopMoveStrategy) : 비숍 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(QueenMoveStrategy) : 퀸 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(KingMoveStrategy) : 킹 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(KnightMoveStrategy) : 나이트 이동 전략에 따른 이동할 수 있는 위치를 계산하는 기능 구현 Co-authored-by: seokmyungham * feat(Row) : 검증 추가 및 검증 테스트 Co-authored-by: seokmyungham * feat(Column) : 검증 추가 및 검증 테스트 Co-authored-by: seokmyungham * feat(ChessGameController) : 도메인과 뷰를 연결하는 컨트롤러 구현 Co-authored-by: seokmyungham * refactor(SpecialPieceMoveStrategy) : 폰을 제외한 특별 기물의 중복 로직을 추상화 Co-authored-by: seokmyungham * refactor(PawnMoveStrategy) : 폰 기물의 중복 로직을 추상화 Co-authored-by: seokmyungham * refactor : 테스트코드가 추상 인터페이스에 의존하도록 리팩터링 Co-authored-by: seokmyungham * fix(WhitePawnMoveStrategy) : 화이트 폰 이동 방향 수정 Co-authored-by: seokmyungham * refactor(ChessGame) : generateMovablePositions 메서드 리팩터링 Co-authored-by: seokmyungham * style : TODO 제거 Co-authored-by: seokmyungham * docs : 구현 기능 목록 동기화 Co-authored-by: seokmyungham * refactor(ChessGame): movePiece 메서드 리팩토링 * refactor(ChessGame): ChessGame 클래스 리팩토링 * fix: 추상 클래스 생성자 접근제한자 protected로 변경 * refactor(Board): initializePawn 메서드 내부 인덴트 1로 수정 * refactor(MoveStrategy): Deque 대신 Queue를 사용하도록 변경 * refactor(Position): 불필요한 toString 제거 * refactor(Row): 가독성 향상을 위해 Enum 이름 변경 * fix: 테스트 클래스 접근 제한자 public 제거 * refactor: 사용자 입력에 대한 관심사를 컨트롤러로 부터 분리 * refactor(OutputView): 체스 판을 의미하는 문자열 상수화 * fix(Command): 클래스 이름 오타 수정 * refactor(Board): 보드 초기화 로직을 별도의 factory 클래스로 분리 * fix(MoveRequestDto): 멤버 변수 private final 키워드 누락 수정 * refactor: 멤버 변수 forwardDirection을 사용하지 않도록 리팩토링 * refactor(ChessGame): 유효한 위치들을 모으는 로직의 중복을 제거 * refactor(PositionsFilter): 이동 가능한 로직만 모으는 로직을 PositionFilter 객체로 분리 * test(BoardTest): 보드 초기화 테스트 추가 * fix(chessGame): 필드 Board 접근 제한자 private으로 수정 * feat(chessGame): 체스 게임에 턴 개념 기능 추가 --------- Co-authored-by: jhon3242 --- README.md | 42 +++++++ src/main/java/.gitkeep | 0 src/main/java/chess/Application.java | 10 ++ .../chess/controller/ChessGameController.java | 66 ++++++++++ src/main/java/chess/domain/board/Board.java | 68 ++++++++++ .../java/chess/domain/board/BoardFactory.java | 52 ++++++++ .../chess/domain/board/position/Column.java | 36 ++++++ .../domain/board/position/Direction.java | 42 +++++++ .../chess/domain/board/position/Position.java | 67 ++++++++++ .../java/chess/domain/board/position/Row.java | 36 ++++++ .../java/chess/domain/game/ChessGame.java | 51 ++++++++ .../chess/domain/game/PositionsFilter.java | 49 ++++++++ src/main/java/chess/domain/piece/Color.java | 13 ++ src/main/java/chess/domain/piece/Piece.java | 75 +++++++++++ .../java/chess/domain/piece/PieceType.java | 34 +++++ .../domain/strategy/BishopMoveStrategy.java | 15 +++ .../strategy/BlackPawnMoveStrategy.java | 14 +++ .../domain/strategy/KingMoveStrategy.java | 18 +++ .../domain/strategy/KnightMoveStrategy.java | 19 +++ .../chess/domain/strategy/MoveStrategy.java | 10 ++ .../domain/strategy/PawnMoveStrategy.java | 43 +++++++ .../domain/strategy/QueenMoveStrategy.java | 18 +++ .../domain/strategy/RookMoveStrategy.java | 14 +++ .../strategy/SpecialPieceMoveStrategy.java | 37 ++++++ .../strategy/WhitePawnMoveStrategy.java | 14 +++ src/main/java/chess/view/Command.java | 23 ++++ src/main/java/chess/view/InputView.java | 34 +++++ src/main/java/chess/view/MoveRequestDto.java | 32 +++++ src/main/java/chess/view/OutputView.java | 46 +++++++ .../java/chess/view/mapper/ColumnMapper.java | 31 +++++ .../java/chess/view/mapper/PieceMapper.java | 36 ++++++ .../java/chess/view/mapper/RowMapper.java | 31 +++++ src/test/java/.gitkeep | 0 .../java/chess/domain/board/BoardTest.java | 72 +++++++++++ .../java/chess/domain/board/ColumnTest.java | 48 +++++++ .../java/chess/domain/board/PositionTest.java | 19 +++ src/test/java/chess/domain/board/RowTest.java | 46 +++++++ .../domain/positionFilter/BishopTest.java | 52 ++++++++ .../domain/positionFilter/BlackPawnTest.java | 118 ++++++++++++++++++ .../chess/domain/positionFilter/KingTest.java | 62 +++++++++ .../domain/positionFilter/KnightTest.java | 63 ++++++++++ .../domain/positionFilter/QueenTest.java | 68 ++++++++++ .../chess/domain/positionFilter/RookTest.java | 58 +++++++++ .../domain/positionFilter/WhitePawnTest.java | 118 ++++++++++++++++++ .../strategy/BishopMoveStrategyTest.java | 88 +++++++++++++ .../strategy/BlackPawnMoveStrategyTest.java | 70 +++++++++++ .../domain/strategy/KingMoveStrategyTest.java | 63 ++++++++++ .../strategy/KnightMoveStrategyTest.java | 59 +++++++++ .../strategy/QueenMoveStrategyTest.java | 79 ++++++++++++ .../domain/strategy/RookMoveStrategyTest.java | 85 +++++++++++++ .../strategy/WhitePawnMoveStrategyTest.java | 76 +++++++++++ .../chess/view/mapper/ColumnMapperTest.java | 37 ++++++ .../java/chess/view/mapper/RowMapperTest.java | 38 ++++++ 53 files changed, 2395 insertions(+) delete mode 100644 src/main/java/.gitkeep create mode 100644 src/main/java/chess/Application.java create mode 100644 src/main/java/chess/controller/ChessGameController.java create mode 100644 src/main/java/chess/domain/board/Board.java create mode 100644 src/main/java/chess/domain/board/BoardFactory.java create mode 100644 src/main/java/chess/domain/board/position/Column.java create mode 100644 src/main/java/chess/domain/board/position/Direction.java create mode 100644 src/main/java/chess/domain/board/position/Position.java create mode 100644 src/main/java/chess/domain/board/position/Row.java create mode 100644 src/main/java/chess/domain/game/ChessGame.java create mode 100644 src/main/java/chess/domain/game/PositionsFilter.java create mode 100644 src/main/java/chess/domain/piece/Color.java create mode 100644 src/main/java/chess/domain/piece/Piece.java create mode 100644 src/main/java/chess/domain/piece/PieceType.java create mode 100644 src/main/java/chess/domain/strategy/BishopMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/BlackPawnMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/KingMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/KnightMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/MoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/PawnMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/QueenMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/RookMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/SpecialPieceMoveStrategy.java create mode 100644 src/main/java/chess/domain/strategy/WhitePawnMoveStrategy.java create mode 100644 src/main/java/chess/view/Command.java create mode 100644 src/main/java/chess/view/InputView.java create mode 100644 src/main/java/chess/view/MoveRequestDto.java create mode 100644 src/main/java/chess/view/OutputView.java create mode 100644 src/main/java/chess/view/mapper/ColumnMapper.java create mode 100644 src/main/java/chess/view/mapper/PieceMapper.java create mode 100644 src/main/java/chess/view/mapper/RowMapper.java delete mode 100644 src/test/java/.gitkeep create mode 100644 src/test/java/chess/domain/board/BoardTest.java create mode 100644 src/test/java/chess/domain/board/ColumnTest.java create mode 100644 src/test/java/chess/domain/board/PositionTest.java create mode 100644 src/test/java/chess/domain/board/RowTest.java create mode 100644 src/test/java/chess/domain/positionFilter/BishopTest.java create mode 100644 src/test/java/chess/domain/positionFilter/BlackPawnTest.java create mode 100644 src/test/java/chess/domain/positionFilter/KingTest.java create mode 100644 src/test/java/chess/domain/positionFilter/KnightTest.java create mode 100644 src/test/java/chess/domain/positionFilter/QueenTest.java create mode 100644 src/test/java/chess/domain/positionFilter/RookTest.java create mode 100644 src/test/java/chess/domain/positionFilter/WhitePawnTest.java create mode 100644 src/test/java/chess/domain/strategy/BishopMoveStrategyTest.java create mode 100644 src/test/java/chess/domain/strategy/BlackPawnMoveStrategyTest.java create mode 100644 src/test/java/chess/domain/strategy/KingMoveStrategyTest.java create mode 100644 src/test/java/chess/domain/strategy/KnightMoveStrategyTest.java create mode 100644 src/test/java/chess/domain/strategy/QueenMoveStrategyTest.java create mode 100644 src/test/java/chess/domain/strategy/RookMoveStrategyTest.java create mode 100644 src/test/java/chess/domain/strategy/WhitePawnMoveStrategyTest.java create mode 100644 src/test/java/chess/view/mapper/ColumnMapperTest.java create mode 100644 src/test/java/chess/view/mapper/RowMapperTest.java diff --git a/README.md b/README.md index 8102f91c870..9117e93cf5f 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,45 @@ ## 우아한테크코스 코드리뷰 - [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) + + +# 기능 구현 목록 + +## 체스 게임 +- [X] : 체스 게임 시작 문구를 출력한다. +- [X] : 시작 명령어를 입력 받는다. + - [X] : start, end 가 아니면 예외를 터트린다. + - [X] : start 입력 시 게임을 시작한다. + - [X] : end 입력 시 게임을 종료한다. +- +- [X] : 보드판을 초기화한다. + - [X] : 소문자, 대문자로 팀을 구분한다. + - [X] : 각 팀은 총 16개의 말을 갖는다. + - [X] : 폰 8개, 룩 2개, 나이트 2개, 비숍 2개, 퀸 1개, 킹 1개 +- [X] : 사용자는 보드판에서 위치로 기물을 조회하여 기물을 이동시킬 수 있다. + + +## 체스 기물 + +### 방향 + - [X] : 북, 북동, 동, 동남, 남, 남서, 서, 북서쪽의 총 8방향을 갖는다. + - [X] : 방향에 따라 방향 가중치 (1, -1, 0)을 갖는다. + +### 위치 + - [X] : 행, 열 enum을 갖는다. + - [X] : 현재 위치를 기준으로 방향에 따른 최대 가중치를 계산한다. + - [X] : 기물이 고유로 갖는 이동 방향과 가중치를 이용하여 이동할 수 있는 위치들을 반환한다. + +### 기물 + - [X] : 기물은 기물 타입을 갖는다. + - [X] : 기물은 팀 색깔을 갖는다. + +### 기물 타입 + - [X] : 기물 타입은 이동 전략을 갖는다. + - [X] : 각 기물의 이동 전략 구현체는 기물의 현재 위치, 방향, 가중치를 가지고 이동할 수 있는 위치들을 계산한다. + - [X] : 룩은 기본적으로 북, 동, 남, 서 방향으로 이동할 수 있다. + - [X] : 비숍은 기본적으로 북동, 동남, 남서, 북서 방향으로 이동할 수 있다. + - [X] : 퀸은 기본적으로 모든 방향으로 이동할 수 있다. + - [X] : 킹은 기본적으로 모든 방향으로 이동할 수 있다. + - [X] : 폰은 기본적으로 팀 색깔에 따라 북 또는 남 방향으로만 이동할 수 있다. + - [X] : 나이트는 기본적으로 북북동, 동북동, 동남동, 남남동, 남남서, 서남서, 서북서, 북북서 방향으로 이동할 수 있다. diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java new file mode 100644 index 00000000000..80af2703622 --- /dev/null +++ b/src/main/java/chess/Application.java @@ -0,0 +1,10 @@ +package chess; + +import chess.controller.ChessGameController; + +public class Application { + public static void main(String[] args) { + ChessGameController chessGameController = new ChessGameController(); + chessGameController.run(); + } +} diff --git a/src/main/java/chess/controller/ChessGameController.java b/src/main/java/chess/controller/ChessGameController.java new file mode 100644 index 00000000000..7f16edb769c --- /dev/null +++ b/src/main/java/chess/controller/ChessGameController.java @@ -0,0 +1,66 @@ +package chess.controller; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.ChessGame; +import chess.view.Command; +import chess.view.InputView; +import chess.view.MoveRequestDto; +import chess.view.OutputView; +import chess.view.mapper.ColumnMapper; +import chess.view.mapper.RowMapper; + +public class ChessGameController { + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + + public void run() { + ChessGame chessGame = new ChessGame(new Board()); + outputView.printStartMessage(); + process(chessGame); + } + + private void process(ChessGame chessGame) { + boolean isRunning = true; + while (isRunning) { + isRunning = processGame(chessGame); + } + } + + private boolean processGame(ChessGame chessGame) { + try { + Command command = inputView.readCommend(); + if (command == Command.START) { + handleStart(chessGame); + } + if (command == Command.MOVE) { + handleMove(chessGame); + } + return command != Command.END; + } catch (IllegalArgumentException error) { + outputView.printError(error); + process(chessGame); + return false; + } + } + + private void handleStart(ChessGame chessGame) { + outputView.printBoard(chessGame.getBoard()); + } + + private void handleMove(ChessGame chessGame) { + MoveRequestDto moveRequestDto = inputView.readPositions(); + Position from = createPosition(moveRequestDto.getFromColumn(), moveRequestDto.getFromRow()); + Position to = createPosition(moveRequestDto.getToColumn(), moveRequestDto.getToRow()); + chessGame.movePiece(from, to); + outputView.printBoard(chessGame.getBoard()); + } + + private Position createPosition(String requestColumn, String requestRow) { + Column column = ColumnMapper.findByInputValue(requestColumn); + Row row = RowMapper.findByInputValue(requestRow); + return new Position(row, column); + } +} diff --git a/src/main/java/chess/domain/board/Board.java b/src/main/java/chess/domain/board/Board.java new file mode 100644 index 00000000000..18b73c41cbc --- /dev/null +++ b/src/main/java/chess/domain/board/Board.java @@ -0,0 +1,68 @@ +package chess.domain.board; + +import chess.domain.board.position.Position; +import chess.domain.piece.Piece; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class Board { + + private final Map board; + + public Board() { + this.board = new HashMap<>(); + BoardFactory boardFactory = new BoardFactory(); + boardFactory.initialize(this); + } + + public Board(Map board) { + this.board = board; + } + + public void movePiece(Position from, Position to) { + Piece piece = board.get(from); + board.put(to, piece); + board.remove(from); + } + + public Piece findPieceByPosition(Position position) { + if (existPiece(position)) { + return board.get(position); + } + throw new IllegalArgumentException("해당 위치에 기물이 없습니다."); + } + + public boolean isEmptySpace(Position position) { + return !existPiece(position); + } + + public boolean existPiece(Position position) { + return board.containsKey(position); + } + + public Map getBoard() { + return board; + } + + void put(Position position, Piece piece) { + board.put(position, piece); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Board other = (Board) o; + return Objects.equals(board, other.board); + } + + @Override + public int hashCode() { + return Objects.hash(board); + } +} diff --git a/src/main/java/chess/domain/board/BoardFactory.java b/src/main/java/chess/domain/board/BoardFactory.java new file mode 100644 index 00000000000..d9fe47d17d7 --- /dev/null +++ b/src/main/java/chess/domain/board/BoardFactory.java @@ -0,0 +1,52 @@ +package chess.domain.board; + +import chess.domain.piece.Color; +import chess.domain.board.position.Column; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; + +public class BoardFactory { + + void initialize(Board board) { + initializeBlackTeam(board); + initializeWhiteTeam(board); + } + + private void initializeBlackTeam(Board board) { + initializePawn(board, Row.SEVEN, Color.BLACK); + initializeHighValuePiece(board, Row.EIGHT, Color.BLACK); + } + + private void initializeWhiteTeam(Board board) { + initializePawn(board, Row.TWO, Color.WHITE); + initializeHighValuePiece(board, Row.ONE, Color.WHITE); + } + + private void initializePawn(Board board, Row row, Color color) { + for (Column column : Column.values()) { + Position position = new Position(row, column); + if (color == Color.WHITE) { + board.put(position, new Piece(PieceType.WHITE_PAWN, color)); + } + if (color == Color.BLACK) { + board.put(position, new Piece(PieceType.BLACK_PAWN, color)); + } + } + } + + private void initializeHighValuePiece(Board board, Row row, Color color) { + board.put(new Position(row, Column.A), new Piece(PieceType.ROOK, color)); + board.put(new Position(row, Column.H), new Piece(PieceType.ROOK, color)); + + board.put(new Position(row, Column.B), new Piece(PieceType.KNIGHT, color)); + board.put(new Position(row, Column.G), new Piece(PieceType.KNIGHT, color)); + + board.put(new Position(row, Column.C), new Piece(PieceType.BISHOP, color)); + board.put(new Position(row, Column.F), new Piece(PieceType.BISHOP, color)); + + board.put(new Position(row, Column.D), new Piece(PieceType.QUEEN, color)); + board.put(new Position(row, Column.E), new Piece(PieceType.KING, color)); + } +} diff --git a/src/main/java/chess/domain/board/position/Column.java b/src/main/java/chess/domain/board/position/Column.java new file mode 100644 index 00000000000..9d81050071f --- /dev/null +++ b/src/main/java/chess/domain/board/position/Column.java @@ -0,0 +1,36 @@ +package chess.domain.board.position; + +import java.util.Arrays; + +public enum Column { + A(0), + B(1), + C(2), + D(3), + E(4), + F(5), + G(6), + H(7); + + private final int index; + + Column(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + public Column calculateNextColumn(int distance) { + return Arrays.stream(values()) + .filter(column -> column.index == this.index + distance) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("일치하는 Column 가 없습니다.")); + } + + public boolean isNextInRange(int distance) { + int nextIndex = index + distance; + return A.index <= nextIndex && nextIndex <= H.index; + } +} diff --git a/src/main/java/chess/domain/board/position/Direction.java b/src/main/java/chess/domain/board/position/Direction.java new file mode 100644 index 00000000000..f31b62a3ddc --- /dev/null +++ b/src/main/java/chess/domain/board/position/Direction.java @@ -0,0 +1,42 @@ +package chess.domain.board.position; + +public enum Direction { + N(-1, 0), + E(0, 1), + S(1, 0), + W(0, -1), + + NE(-1, 1), + SE(1, 1), + SW(1, -1), + NW(-1, -1), + + NNE(-2, 1), + ENE(-1, 2), + ESE(1, 2), + SSE(2, 1), + SSW(2, -1), + WSW(1, -2), + WNW(-1, -2), + NNW(-2, -1); + + private final int rowDirection; + private final int columnDirection; + + Direction(int rowDirection, int columnDirection) { + this.rowDirection = rowDirection; + this.columnDirection = columnDirection; + } + + public boolean isStraight() { + return this == Direction.N || this == Direction.S || this == Direction.E || this == Direction.W; + } + + public int calculateRowDistance(int weight) { + return rowDirection * weight; + } + + public int calculateColumnDistance(int weight) { + return columnDirection * weight; + } +} diff --git a/src/main/java/chess/domain/board/position/Position.java b/src/main/java/chess/domain/board/position/Position.java new file mode 100644 index 00000000000..96be2b7a6f3 --- /dev/null +++ b/src/main/java/chess/domain/board/position/Position.java @@ -0,0 +1,67 @@ +package chess.domain.board.position; + +import java.util.Objects; +import java.util.stream.IntStream; + +public class Position { + + private final Row row; + private final Column column; + + public Position(Row row, Column column) { + this.row = row; + this.column = column; + } + + public Position calculateNextPosition(Direction direction, int weight) { + int rowDistance = direction.calculateRowDistance(weight); + int columnDistance = direction.calculateColumnDistance(weight); + + Row nextRow = row.calculateNextRow(rowDistance); + Column nextColumn = column.calculateNextColumn(columnDistance); + return new Position(nextRow, nextColumn); + } + + public int calculateMaxDistance(Direction direction, int maxMoveDistance) { + return IntStream.rangeClosed(1, maxMoveDistance) + .filter(weight -> isInRange(direction, weight)) + .max() + .orElse(0); + } + + private boolean isInRange(Direction direction, int weight) { + int rowDistance = direction.calculateRowDistance(weight); + int columnDistance = direction.calculateColumnDistance(weight); + + return row.isNextInRange(rowDistance) && column.isNextInRange(columnDistance); + } + + public boolean isSameRow(Row row) { + return this.row == row; + } + + public int getRowIndex() { + return row.getIndex(); + } + + public int getColumnIndex() { + return column.getIndex(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Position position = (Position) o; + return column == position.column && row == position.row; + } + + @Override + public int hashCode() { + return Objects.hash(column, row); + } +} diff --git a/src/main/java/chess/domain/board/position/Row.java b/src/main/java/chess/domain/board/position/Row.java new file mode 100644 index 00000000000..f82305f6327 --- /dev/null +++ b/src/main/java/chess/domain/board/position/Row.java @@ -0,0 +1,36 @@ +package chess.domain.board.position; + +import java.util.Arrays; + +public enum Row { + ONE(7), + TWO(6), + THREE(5), + FOUR(4), + FIVE(3), + SIX(2), + SEVEN(1), + EIGHT(0); + + private final int index; + + Row(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + public Row calculateNextRow(int distance) { + return Arrays.stream(values()) + .filter(row -> row.index == this.index + distance) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("일치하는 Column 이 없습니다.")); + } + + public boolean isNextInRange(int distance) { + int nextIndex = index + distance; + return EIGHT.index <= nextIndex && nextIndex <= ONE.index; + } +} diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java new file mode 100644 index 00000000000..d0ae16e92b5 --- /dev/null +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -0,0 +1,51 @@ +package chess.domain.game; + +import chess.domain.board.Board; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +public class ChessGame { + + private static final Color START_TURN = Color.WHITE; + + private final Board board; + private Color currentTurn; + + public ChessGame(Board board) { + this.board = board; + currentTurn = START_TURN; + } + + public void movePiece(Position from, Position to) { + validateUserTurn(from); + List movablePositions = generateMovablePositions(from); + if (movablePositions.contains(to)) { + board.movePiece(from, to); + currentTurn = currentTurn.change(); + return; + } + throw new IllegalArgumentException("기물을 해당 위치로 이동시킬 수 없습니다."); + } + + private void validateUserTurn(Position from) { + Piece piece = board.findPieceByPosition(from); + if (piece.isNotSameColor(currentTurn)) { + throw new IllegalArgumentException("상대방의 기물을 움직일 수 없습니다. 현재 턴 : " + currentTurn); + } + } + + private List generateMovablePositions(Position position) { + Piece piece = board.findPieceByPosition(position); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + return new PositionsFilter().generateValidPositions(candidateAllPositions, piece, board); + } + + public Board getBoard() { + return board; + } +} diff --git a/src/main/java/chess/domain/game/PositionsFilter.java b/src/main/java/chess/domain/game/PositionsFilter.java new file mode 100644 index 00000000000..93813c1512e --- /dev/null +++ b/src/main/java/chess/domain/game/PositionsFilter.java @@ -0,0 +1,49 @@ +package chess.domain.game; + +import chess.domain.board.Board; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.piece.Piece; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +public class PositionsFilter { + + public List generateValidPositions(Map> candidateAllPositions, + Piece piece, + Board board) { + return candidateAllPositions.keySet().stream() + .map(direction -> filterInvalidPositions(candidateAllPositions.get(direction), direction, piece, board)) + .flatMap(List::stream) + .toList(); + } + + private List filterInvalidPositions(Queue expectedPositions, Direction direction, + Piece piece, Board board) { + List result = new ArrayList<>(); + Position currentPosition = expectedPositions.poll(); + while (isEmptySpace(direction, piece, currentPosition, board)) { + result.add(currentPosition); + currentPosition = expectedPositions.poll(); + } + if (isEnemySpace(direction, piece, currentPosition, board)) { + result.add(currentPosition); + } + return result; + } + + private boolean isEmptySpace(Direction direction, Piece piece, Position currentPosition, Board board) { + return currentPosition != null + && piece.isPawnMovePossible(direction) + && board.isEmptySpace(currentPosition); + } + + private boolean isEnemySpace(Direction direction, Piece piece, Position currentPosition, Board board) { + return currentPosition != null + && piece.isPawnAttackPossible(direction) + && board.existPiece(currentPosition) + && board.findPieceByPosition(currentPosition).isEnemy(piece); + } +} diff --git a/src/main/java/chess/domain/piece/Color.java b/src/main/java/chess/domain/piece/Color.java new file mode 100644 index 00000000000..b380cc7e1ea --- /dev/null +++ b/src/main/java/chess/domain/piece/Color.java @@ -0,0 +1,13 @@ +package chess.domain.piece; + +public enum Color { + BLACK, + WHITE; + + public Color change() { + if (this == BLACK) { + return WHITE; + } + return BLACK; + } +} diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java new file mode 100644 index 00000000000..82a512f67a2 --- /dev/null +++ b/src/main/java/chess/domain/piece/Piece.java @@ -0,0 +1,75 @@ +package chess.domain.piece; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import java.util.Map; +import java.util.Objects; +import java.util.Queue; + +public class Piece { + + private final PieceType pieceType; + private final Color color; + + public Piece(PieceType pieceType, Color color) { + this.pieceType = pieceType; + this.color = color; + } + + public Map> generateAllDirectionPositions(Position currentPosition) { + return pieceType.generateAllDirectionPositions(currentPosition); + } + + public boolean isEnemy(Piece piece) { + return isNotSameColor(piece.color); + } + + public boolean isBlack() { + return this.color == Color.BLACK; + } + + public boolean isNotSameColor(Color turn) { + return this.color != turn; + } + + public boolean isPawnAttackPossible(Direction direction) { + if (pieceType == PieceType.BLACK_PAWN) { + return direction == Direction.SW || direction == Direction.SE; + } + if (pieceType == PieceType.WHITE_PAWN) { + return direction == Direction.NW || direction == Direction.NE; + } + return true; + } + + public boolean isPawnMovePossible(Direction direction) { + if (pieceType == PieceType.BLACK_PAWN) { + return direction == Direction.S; + } + if (pieceType == PieceType.WHITE_PAWN) { + return direction == Direction.N; + } + return true; + } + + public PieceType getPieceType() { + return pieceType; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Piece piece = (Piece) o; + return pieceType == piece.pieceType && color == piece.color; + } + + @Override + public int hashCode() { + return Objects.hash(pieceType, color); + } +} diff --git a/src/main/java/chess/domain/piece/PieceType.java b/src/main/java/chess/domain/piece/PieceType.java new file mode 100644 index 00000000000..8c60b98132a --- /dev/null +++ b/src/main/java/chess/domain/piece/PieceType.java @@ -0,0 +1,34 @@ +package chess.domain.piece; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.strategy.BishopMoveStrategy; +import chess.domain.strategy.BlackPawnMoveStrategy; +import chess.domain.strategy.KingMoveStrategy; +import chess.domain.strategy.KnightMoveStrategy; +import chess.domain.strategy.MoveStrategy; +import chess.domain.strategy.QueenMoveStrategy; +import chess.domain.strategy.RookMoveStrategy; +import chess.domain.strategy.WhitePawnMoveStrategy; +import java.util.Map; +import java.util.Queue; + +public enum PieceType { + BLACK_PAWN(new BlackPawnMoveStrategy()), + WHITE_PAWN(new WhitePawnMoveStrategy()), + ROOK(new RookMoveStrategy()), + KNIGHT(new KnightMoveStrategy()), + BISHOP(new BishopMoveStrategy()), + QUEEN(new QueenMoveStrategy()), + KING(new KingMoveStrategy()); + + private final MoveStrategy moveStrategy; + + PieceType(MoveStrategy moveStrategy) { + this.moveStrategy = moveStrategy; + } + + public Map> generateAllDirectionPositions(Position currentPosition) { + return this.moveStrategy.generateMovablePositions(currentPosition); + } +} diff --git a/src/main/java/chess/domain/strategy/BishopMoveStrategy.java b/src/main/java/chess/domain/strategy/BishopMoveStrategy.java new file mode 100644 index 00000000000..0ce1273c404 --- /dev/null +++ b/src/main/java/chess/domain/strategy/BishopMoveStrategy.java @@ -0,0 +1,15 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import java.util.List; + +public class BishopMoveStrategy extends SpecialPieceMoveStrategy{ + + private static final int DEFAULT_MAX_MOVE_DISTANCE = 7; + + private static final List DIRECTIONS = List.of(Direction.NE, Direction.SE, Direction.SW, Direction.NW); + + public BishopMoveStrategy() { + super(DIRECTIONS, DEFAULT_MAX_MOVE_DISTANCE); + } +} diff --git a/src/main/java/chess/domain/strategy/BlackPawnMoveStrategy.java b/src/main/java/chess/domain/strategy/BlackPawnMoveStrategy.java new file mode 100644 index 00000000000..6000c704f18 --- /dev/null +++ b/src/main/java/chess/domain/strategy/BlackPawnMoveStrategy.java @@ -0,0 +1,14 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Row; +import java.util.List; + +public class BlackPawnMoveStrategy extends PawnMoveStrategy{ + + private static final List DIRECTIONS = List.of(Direction.S, Direction.SE, Direction.SW); + + public BlackPawnMoveStrategy() { + super(DIRECTIONS, Row.SEVEN); + } +} diff --git a/src/main/java/chess/domain/strategy/KingMoveStrategy.java b/src/main/java/chess/domain/strategy/KingMoveStrategy.java new file mode 100644 index 00000000000..190a330c4e9 --- /dev/null +++ b/src/main/java/chess/domain/strategy/KingMoveStrategy.java @@ -0,0 +1,18 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import java.util.List; + +public class KingMoveStrategy extends SpecialPieceMoveStrategy{ + + private static final int DEFAULT_MAX_MOVE_DISTANCE = 1; + + private static final List DIRECTIONS = List.of( + Direction.N, Direction.NE, Direction.E, Direction.SE, + Direction.S, Direction.SW, Direction.W, Direction.NW + ); + + public KingMoveStrategy() { + super(DIRECTIONS, DEFAULT_MAX_MOVE_DISTANCE); + } +} diff --git a/src/main/java/chess/domain/strategy/KnightMoveStrategy.java b/src/main/java/chess/domain/strategy/KnightMoveStrategy.java new file mode 100644 index 00000000000..0cba1cd1f9b --- /dev/null +++ b/src/main/java/chess/domain/strategy/KnightMoveStrategy.java @@ -0,0 +1,19 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import java.util.List; + +public class KnightMoveStrategy extends SpecialPieceMoveStrategy{ + + private static final int DEFAULT_MAX_MOVE_DISTANCE = 1; + + private static final List DIRECTIONS = List.of( + Direction.NNE, Direction.ENE, Direction.ESE, Direction.SSE, + Direction.SSW, Direction.WSW, Direction.WNW, Direction.NNW + ); + + + public KnightMoveStrategy() { + super(DIRECTIONS, DEFAULT_MAX_MOVE_DISTANCE); + } +} diff --git a/src/main/java/chess/domain/strategy/MoveStrategy.java b/src/main/java/chess/domain/strategy/MoveStrategy.java new file mode 100644 index 00000000000..2176179470c --- /dev/null +++ b/src/main/java/chess/domain/strategy/MoveStrategy.java @@ -0,0 +1,10 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import java.util.Queue; +import java.util.Map; + +public interface MoveStrategy { + Map> generateMovablePositions(Position position); +} diff --git a/src/main/java/chess/domain/strategy/PawnMoveStrategy.java b/src/main/java/chess/domain/strategy/PawnMoveStrategy.java new file mode 100644 index 00000000000..71db6885c4c --- /dev/null +++ b/src/main/java/chess/domain/strategy/PawnMoveStrategy.java @@ -0,0 +1,43 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.ArrayDeque; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public abstract class PawnMoveStrategy implements MoveStrategy { + + private static final int DEFAULT_MAX_MOVE_DISTANCE = 1; + + private final List directions; + private final Row startRow; + + protected PawnMoveStrategy(List directions, Row startRow) { + this.directions = directions; + this.startRow = startRow; + } + + @Override + public Map> generateMovablePositions(Position position) { + return directions.stream() + .collect(Collectors.toMap( + direction -> direction, + direction -> generateMovablePositionsByDirection(position, direction) + )); + } + + private Queue generateMovablePositionsByDirection(Position currentPosition, Direction direction) { + int movableMaxDistance = currentPosition.calculateMaxDistance(direction, DEFAULT_MAX_MOVE_DISTANCE); + if (currentPosition.isSameRow(startRow) && direction.isStraight()) { + movableMaxDistance++; + } + return new ArrayDeque<>(IntStream.rangeClosed(1, movableMaxDistance) + .mapToObj(weight -> currentPosition.calculateNextPosition(direction, weight)) + .toList()); + } +} diff --git a/src/main/java/chess/domain/strategy/QueenMoveStrategy.java b/src/main/java/chess/domain/strategy/QueenMoveStrategy.java new file mode 100644 index 00000000000..4b6b03ca12a --- /dev/null +++ b/src/main/java/chess/domain/strategy/QueenMoveStrategy.java @@ -0,0 +1,18 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import java.util.List; + +public class QueenMoveStrategy extends SpecialPieceMoveStrategy{ + + private static final int DEFAULT_MAX_MOVE_DISTANCE = 7; + + private static final List DIRECTIONS = List.of( + Direction.N, Direction.NE, Direction.E, Direction.SE, + Direction.S, Direction.SW, Direction.W, Direction.NW + ); + + public QueenMoveStrategy() { + super(DIRECTIONS, DEFAULT_MAX_MOVE_DISTANCE); + } +} diff --git a/src/main/java/chess/domain/strategy/RookMoveStrategy.java b/src/main/java/chess/domain/strategy/RookMoveStrategy.java new file mode 100644 index 00000000000..6352979762d --- /dev/null +++ b/src/main/java/chess/domain/strategy/RookMoveStrategy.java @@ -0,0 +1,14 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import java.util.List; + +public class RookMoveStrategy extends SpecialPieceMoveStrategy{ + + private static final int DEFAULT_MAX_MOVE_DISTANCE = 7; + private static final List DIRECTIONS = List.of(Direction.N, Direction.W, Direction.S, Direction.E); + + public RookMoveStrategy() { + super(DIRECTIONS, DEFAULT_MAX_MOVE_DISTANCE); + } +} diff --git a/src/main/java/chess/domain/strategy/SpecialPieceMoveStrategy.java b/src/main/java/chess/domain/strategy/SpecialPieceMoveStrategy.java new file mode 100644 index 00000000000..edcadce6a66 --- /dev/null +++ b/src/main/java/chess/domain/strategy/SpecialPieceMoveStrategy.java @@ -0,0 +1,37 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public abstract class SpecialPieceMoveStrategy implements MoveStrategy { + + private final List directions; + private final int defaultMaxMoveDistance; + + protected SpecialPieceMoveStrategy(List directions, int defaultMaxMoveDistance) { + this.directions = directions; + this.defaultMaxMoveDistance = defaultMaxMoveDistance; + } + + @Override + public Map> generateMovablePositions(Position position) { + return directions.stream() + .collect(Collectors.toMap( + direction -> direction, + direction -> generateMovablePositionsByDirection(position, direction) + )); + } + + private Queue generateMovablePositionsByDirection(Position currentPosition, Direction direction) { + int movableMaxDistance = currentPosition.calculateMaxDistance(direction, defaultMaxMoveDistance); + return new ArrayDeque<>(IntStream.rangeClosed(1, movableMaxDistance) + .mapToObj(weight -> currentPosition.calculateNextPosition(direction, weight)) + .toList()); + } +} diff --git a/src/main/java/chess/domain/strategy/WhitePawnMoveStrategy.java b/src/main/java/chess/domain/strategy/WhitePawnMoveStrategy.java new file mode 100644 index 00000000000..b0ff8a5941a --- /dev/null +++ b/src/main/java/chess/domain/strategy/WhitePawnMoveStrategy.java @@ -0,0 +1,14 @@ +package chess.domain.strategy; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Row; +import java.util.List; + +public class WhitePawnMoveStrategy extends PawnMoveStrategy{ + + private static final List DIRECTIONS = List.of(Direction.N, Direction.NE, Direction.NW); + + public WhitePawnMoveStrategy() { + super(DIRECTIONS, Row.TWO); + } +} diff --git a/src/main/java/chess/view/Command.java b/src/main/java/chess/view/Command.java new file mode 100644 index 00000000000..32b8c8a9a5e --- /dev/null +++ b/src/main/java/chess/view/Command.java @@ -0,0 +1,23 @@ +package chess.view; + +import java.util.Arrays; + +public enum Command { + START("start"), END("end"), MOVE("move"); + + private final String value; + + Command(String value) { + this.value = value; + } + + public static Command inputToCommend(String input) { + if (input == null || input.isBlank()) { + throw new IllegalArgumentException("빈 값 입력을 허용하지 않습니다."); + } + return Arrays.stream(values()) + .filter(command -> command.value.equals(input)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("옳바르지 않은 명령어 입력입니다.")); + } +} diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java new file mode 100644 index 00000000000..12124e22731 --- /dev/null +++ b/src/main/java/chess/view/InputView.java @@ -0,0 +1,34 @@ +package chess.view; + +import java.util.Scanner; +import java.util.regex.Pattern; + +public class InputView { + + private static final Pattern COMMAND_REGEX = Pattern.compile("(move)|(start)|(end)"); + private static final Pattern POSITION_REGEX = Pattern.compile("([a-h][1-8]\\s+[a-h][1-8])"); + + private final Scanner scanner = new Scanner(System.in); + + public Command readCommend() { + String input = scanner.next(); + if (!COMMAND_REGEX.matcher(input).matches()) { + throw new IllegalArgumentException("입력한 체스 게임 명령어가 올바르지 않습니다."); + } + return Command.inputToCommend(input); + } + + public MoveRequestDto readPositions() { + String input = scanner.nextLine().strip(); + if (!POSITION_REGEX.matcher(input).matches()) { + throw new IllegalArgumentException("입력한 이동 명령 형식이 올바르지 않습니다."); + } + + return new MoveRequestDto( + input.substring(0, 1), + input.substring(1, 2), + input.substring(3, 4), + input.substring(4, 5) + ); + } +} diff --git a/src/main/java/chess/view/MoveRequestDto.java b/src/main/java/chess/view/MoveRequestDto.java new file mode 100644 index 00000000000..74e67b36383 --- /dev/null +++ b/src/main/java/chess/view/MoveRequestDto.java @@ -0,0 +1,32 @@ +package chess.view; + +public class MoveRequestDto { + + private final String fromColumn; + private final String fromRow; + private final String toColumn; + private final String toRow; + + public MoveRequestDto(String fromColumn, String fromRow, String toColumn, String toRow) { + this.fromColumn = fromColumn; + this.fromRow = fromRow; + this.toColumn = toColumn; + this.toRow = toRow; + } + + public String getFromColumn() { + return fromColumn; + } + + public String getFromRow() { + return fromRow; + } + + public String getToColumn() { + return toColumn; + } + + public String getToRow() { + return toRow; + } +} diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java new file mode 100644 index 00000000000..6871626313e --- /dev/null +++ b/src/main/java/chess/view/OutputView.java @@ -0,0 +1,46 @@ +package chess.view; + +import chess.domain.piece.Piece; +import chess.domain.board.Board; +import chess.view.mapper.PieceMapper; +import java.util.ArrayList; +import java.util.List; + +public class OutputView { + + private static final String EMPTY_BOARD = "........"; + + public void printStartMessage() { + System.out.println("체스 게임을 시작합니다."); + System.out.println("게임 시작 : start"); + System.out.println("게임 종료 : end"); + System.out.println("게임 이동 : move source위치 target위치 - 예. move b2 b3"); + } + + public void printBoard(Board board) { + List result = new ArrayList<>(); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD)); + + board.getBoard().keySet() + .forEach(position -> { + Piece piece = board.getBoard().get(position); + int rowIndex = position.getRowIndex(); + int columnIndex = position.getColumnIndex(); + result.get(rowIndex).replace(columnIndex, columnIndex + 1, PieceMapper.findByPieceType(piece)); + }); + + result.forEach(System.out::println); + System.out.println(); + } + + public void printError(Exception exception) { + System.out.println(exception.getMessage()); + } +} diff --git a/src/main/java/chess/view/mapper/ColumnMapper.java b/src/main/java/chess/view/mapper/ColumnMapper.java new file mode 100644 index 00000000000..dc0d08a264d --- /dev/null +++ b/src/main/java/chess/view/mapper/ColumnMapper.java @@ -0,0 +1,31 @@ +package chess.view.mapper; + +import chess.domain.board.position.Column; +import java.util.Arrays; + +public enum ColumnMapper { + A(Column.A, "a"), + B(Column.B, "b"), + C(Column.C, "c"), + D(Column.D, "d"), + E(Column.E, "e"), + F(Column.F, "f"), + G(Column.G, "g"), + H(Column.H, "h"); + + private final Column column; + private final String value; + + ColumnMapper(Column column, String value) { + this.column = column; + this.value = value; + } + + public static Column findByInputValue(String value) { + return Arrays.stream(values()) + .filter(column -> column.value.equals(value)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("일치하는 Column 이 없습니다.")) + .column; + } +} diff --git a/src/main/java/chess/view/mapper/PieceMapper.java b/src/main/java/chess/view/mapper/PieceMapper.java new file mode 100644 index 00000000000..fa00ae8d847 --- /dev/null +++ b/src/main/java/chess/view/mapper/PieceMapper.java @@ -0,0 +1,36 @@ +package chess.view.mapper; + +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.Arrays; + +public enum PieceMapper { + + BLACK_PAWN(PieceType.BLACK_PAWN, "P"), + WHITE_PAWN(PieceType.WHITE_PAWN, "p"), + ROOK(PieceType.ROOK, "r"), + KNIGHT(PieceType.KNIGHT, "n"), + BISHOP(PieceType.BISHOP, "b"), + QUEEN(PieceType.QUEEN, "q"), + KING(PieceType.KING, "k"); + + private final PieceType pieceType; + private final String value; + + PieceMapper(PieceType pieceType, String value) { + this.pieceType = pieceType; + this.value = value; + } + + public static String findByPieceType(Piece piece) { + String value = Arrays.stream(values()) + .filter(pieceMapper -> piece.getPieceType() == pieceMapper.pieceType) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("일치하는 기물이 없습니다.")) + .value; + if (piece.isBlack()) { + return value.toUpperCase(); + } + return value; + } +} diff --git a/src/main/java/chess/view/mapper/RowMapper.java b/src/main/java/chess/view/mapper/RowMapper.java new file mode 100644 index 00000000000..6242990d472 --- /dev/null +++ b/src/main/java/chess/view/mapper/RowMapper.java @@ -0,0 +1,31 @@ +package chess.view.mapper; + +import chess.domain.board.position.Row; +import java.util.Arrays; + +public enum RowMapper { + RANK1(Row.ONE, "1"), + RANK2(Row.TWO, "2"), + RANK3(Row.THREE, "3"), + RANK4(Row.FOUR, "4"), + RANK5(Row.FIVE, "5"), + RANK6(Row.SIX, "6"), + RANK7(Row.SEVEN, "7"), + RANK8(Row.EIGHT, "8"); + + private final Row row; + private final String value; + + RowMapper(Row row, String value) { + this.row = row; + this.value = value; + } + + public static Row findByInputValue(String value) { + return Arrays.stream(values()) + .filter(row -> row.value.equals(value)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("일치하는 Column 이 없습니다.")) + .row; + } +} diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/test/java/chess/domain/board/BoardTest.java b/src/test/java/chess/domain/board/BoardTest.java new file mode 100644 index 00000000000..00354f990e1 --- /dev/null +++ b/src/test/java/chess/domain/board/BoardTest.java @@ -0,0 +1,72 @@ +package chess.domain.board; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class BoardTest { + + @Test + @DisplayName("보드 생성 시 32개의 기물이 초기화된다.") + void printMap() { + Board board = new Board(); + + Map boardMap = board.getBoard(); + + assertThat(boardMap).hasSize(32); + } + + @Test + @DisplayName("보드 팩토리로 체스 시작 보드가 정상적으로 초기화 된다") + void boardInitializeTest() { + Map map = new HashMap<>(); + map.put(new Position(Row.ONE, Column.A), new Piece(PieceType.ROOK, Color.WHITE)); + map.put(new Position(Row.ONE, Column.H), new Piece(PieceType.ROOK, Color.WHITE)); + map.put(new Position(Row.ONE, Column.B), new Piece(PieceType.KNIGHT, Color.WHITE)); + map.put(new Position(Row.ONE, Column.G), new Piece(PieceType.KNIGHT, Color.WHITE)); + map.put(new Position(Row.ONE, Column.C), new Piece(PieceType.BISHOP, Color.WHITE)); + map.put(new Position(Row.ONE, Column.F), new Piece(PieceType.BISHOP, Color.WHITE)); + map.put(new Position(Row.ONE, Column.D), new Piece(PieceType.QUEEN, Color.WHITE)); + map.put(new Position(Row.ONE, Column.E), new Piece(PieceType.KING, Color.WHITE)); + + map.put(new Position(Row.TWO, Column.A), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.H), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.G), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.F), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.D), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + + map.put(new Position(Row.EIGHT, Column.A), new Piece(PieceType.ROOK, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.H), new Piece(PieceType.ROOK, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.B), new Piece(PieceType.KNIGHT, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.G), new Piece(PieceType.KNIGHT, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.C), new Piece(PieceType.BISHOP, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.F), new Piece(PieceType.BISHOP, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.D), new Piece(PieceType.QUEEN, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.E), new Piece(PieceType.KING, Color.BLACK)); + + map.put(new Position(Row.SEVEN, Column.A), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.H), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.B), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.G), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + + Board board = new Board(); + + assertThat(new Board(map)).isEqualTo(board); + } +} diff --git a/src/test/java/chess/domain/board/ColumnTest.java b/src/test/java/chess/domain/board/ColumnTest.java new file mode 100644 index 00000000000..d792a59f8f3 --- /dev/null +++ b/src/test/java/chess/domain/board/ColumnTest.java @@ -0,0 +1,48 @@ +package chess.domain.board; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import chess.domain.board.position.Column; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ColumnTest { + + @Test + @DisplayName("거리 만큼 이동한 Column를 반환한다.") + void calculateNextColumnSuccessTest() { + Column column = Column.E; + + assertAll( + () -> assertEquals(Column.D, column.calculateNextColumn(-1)), + () -> assertEquals(Column.F, column.calculateNextColumn(1)), + () -> assertEquals(Column.E, column.calculateNextColumn(0)) + ); + } + + @Test + @DisplayName("거리 만큼 이동한 값이 보드판을 벗어난 경우 에러를 반환한다.") + void calculateNextColumnFailTest() { + Column column = Column.D; + + assertThatThrownBy(() -> column.calculateNextColumn(-5)) + .isInstanceOf(IllegalArgumentException.class); + } + + + + @Test + @DisplayName("거리 만큼 이동한 값이 보드판을 벗어난 경우 false를 반환한다.") + void isNextInRange() { + assertAll( + () -> assertFalse(Column.A.isNextInRange(-1)), + () -> assertFalse(Column.H.isNextInRange(1)), + () -> assertTrue(Column.A.isNextInRange(1)), + () -> assertTrue(Column.H.isNextInRange(-1)) + ); + } +} diff --git a/src/test/java/chess/domain/board/PositionTest.java b/src/test/java/chess/domain/board/PositionTest.java new file mode 100644 index 00000000000..d87b8ba5a46 --- /dev/null +++ b/src/test/java/chess/domain/board/PositionTest.java @@ -0,0 +1,19 @@ +package chess.domain.board; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PositionTest { + + @Test + @DisplayName("포지션 생성 테스트") + void constructTest() { + Position position = new Position(Row.THREE, Column.H); + + Assertions.assertThat(position).isNotNull(); + } +} diff --git a/src/test/java/chess/domain/board/RowTest.java b/src/test/java/chess/domain/board/RowTest.java new file mode 100644 index 00000000000..f074a1013b3 --- /dev/null +++ b/src/test/java/chess/domain/board/RowTest.java @@ -0,0 +1,46 @@ +package chess.domain.board; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import chess.domain.board.position.Row; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RowTest { + + @Test + @DisplayName("거리 만큼 이동한 Row를 반환한다.") + void calculateNextRowSuccessTest() { + Row row = Row.FOUR; + + assertAll( + () -> assertEquals(Row.FIVE, row.calculateNextRow(-1)), + () -> assertEquals(Row.THREE, row.calculateNextRow(1)), + () -> assertEquals(Row.FOUR, row.calculateNextRow(0)) + ); + } + + @Test + @DisplayName("거리 만큼 이동한 값이 보드판을 벗어난 경우 에러를 반환한다.") + void calculateNextRowFailTest() { + Row row = Row.FOUR; + + assertThatThrownBy(() -> row.calculateNextRow(-5)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("거리 만큼 이동한 값이 보드판을 벗어난 경우 false를 반환한다.") + void isNextInRange() { + assertAll( + () -> assertTrue(Row.FOUR.isNextInRange(-1)), + () -> assertTrue(Row.FOUR.isNextInRange(1)), + () -> assertFalse(Row.EIGHT.isNextInRange(-1)), + () -> assertFalse(Row.ONE.isNextInRange(1)) + ); + } +} diff --git a/src/test/java/chess/domain/positionFilter/BishopTest.java b/src/test/java/chess/domain/positionFilter/BishopTest.java new file mode 100644 index 00000000000..118acdea67d --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/BishopTest.java @@ -0,0 +1,52 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class BishopTest { + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ....P... 3 + * .p...... 2 + * ..b..... 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") + void generateMovablePositions() { + Position position = new Position(Row.ONE, Column.C); + Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.TWO, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.THREE, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.TWO, Column.D), + new Position(Row.THREE, Column.E) + ); + } +} diff --git a/src/test/java/chess/domain/positionFilter/BlackPawnTest.java b/src/test/java/chess/domain/positionFilter/BlackPawnTest.java new file mode 100644 index 00000000000..2ab182b407c --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/BlackPawnTest.java @@ -0,0 +1,118 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class BlackPawnTest { + /** + * ........ 8 (rank 8) + * ...P.... 7 + * ..r.r... 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ........ 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("블랙 폰 시작 위치에서 양쪽 대각선에 상대 기물이 있고 앞 2칸은 비어있다.") + void startPositionPawnWithOnlyAttackablePositions() { + Position position = new Position(Row.SEVEN, Column.D); + Piece piece = new Piece(PieceType.BLACK_PAWN, Color.BLACK); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.SIX, Column.C), new Piece(PieceType.ROOK, Color.WHITE), + new Position(Row.SIX, Column.E), new Piece(PieceType.ROOK, Color.WHITE) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.C), + new Position(Row.SIX, Column.E), + new Position(Row.SIX, Column.D), + new Position(Row.FIVE, Column.D) + ); + } + + /** + * ........ 8 (rank 8) + * ...P.... 7 + * ..P..... 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ........ 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("블랙 폰 시작 위치에서 앞으로만 이동할 수 있는 경우") + void startPositionPawnWithFreePositions() { + Position position = new Position(Row.SEVEN, Column.D); + Piece piece = new Piece(PieceType.BLACK_PAWN, Color.BLACK); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.SIX, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.D), + new Position(Row.FIVE, Column.D) + ); + } + + /** + * ........ 8 (rank 8) + * ...P.... 7 + * ..Pp.... 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ........ 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("블랙 폰 시작 위치에서 움직일 수 없는 경우") + void startPositionPawnWithCantMovePositions() { + Position position = new Position(Row.SEVEN, Column.D); + Piece piece = new Piece(PieceType.BLACK_PAWN, Color.BLACK); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.SIX, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.SIX, Column.D), new Piece(PieceType.BLACK_PAWN, Color.WHITE) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).isEmpty(); + } +} diff --git a/src/test/java/chess/domain/positionFilter/KingTest.java b/src/test/java/chess/domain/positionFilter/KingTest.java new file mode 100644 index 00000000000..055f06da45c --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/KingTest.java @@ -0,0 +1,62 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class KingTest { + /** + * ........ 8 (rank 8) + * ...P.... 7 + * ........ 6 + * ........ 5 + * .....P.. 4 + * ..p..... 3 + * ..Pkp... 2 + * ..NbR... 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") + void generateMovablePositions() { + Position position = new Position(Row.TWO, Column.D); + Piece piece = new Piece(PieceType.KING, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.TWO, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.ONE, Column.D), new Piece(PieceType.BISHOP, Color.WHITE), + new Position(Row.THREE, Column.C), new Piece(PieceType.BLACK_PAWN, Color.WHITE), + new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.FOUR, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.ONE, Column.E), new Piece(PieceType.ROOK, Color.BLACK), + new Position(Row.ONE, Column.C), new Piece(PieceType.KNIGHT, Color.BLACK), + new Position(Row.TWO, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK) + + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.THREE, Column.D), + new Position(Row.THREE, Column.E), + new Position(Row.ONE, Column.E), + new Position(Row.ONE, Column.C), + new Position(Row.TWO, Column.C) + ); + } +} diff --git a/src/test/java/chess/domain/positionFilter/KnightTest.java b/src/test/java/chess/domain/positionFilter/KnightTest.java new file mode 100644 index 00000000000..f0b2cef5e10 --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/KnightTest.java @@ -0,0 +1,63 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class KnightTest { + /** + * ........ 8 (rank 8) + * ........ 7 + * ..r.P... 6 + * ..P.P... 5 + * ...np... 4 + * .B.ppq.. 3 + * ........ 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") + void generateMovablePositions() { + Position position = new Position(Row.FOUR, Column.D); + Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.THREE, Column.F), new Piece(PieceType.QUEEN, Color.WHITE), + new Position(Row.SIX, Column.C), new Piece(PieceType.ROOK, Color.WHITE), + new Position(Row.FOUR, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.THREE, Column.D), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.THREE, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.SIX, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.FIVE, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.FIVE, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.THREE, Column.B), new Piece(PieceType.BISHOP, Color.BLACK) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.E), + new Position(Row.FIVE, Column.F), + new Position(Row.TWO, Column.E), + new Position(Row.TWO, Column.C), + new Position(Row.THREE, Column.B), + new Position(Row.FIVE, Column.B) + ); + } +} diff --git a/src/test/java/chess/domain/positionFilter/QueenTest.java b/src/test/java/chess/domain/positionFilter/QueenTest.java new file mode 100644 index 00000000000..e2d557aba27 --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/QueenTest.java @@ -0,0 +1,68 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class QueenTest { + + /** + * ........ 8 (rank 8) + * ...P.... 7 + * ........ 6 + * ........ 5 + * .....P.. 4 + * ..p..... 3 + * ..Pqp... 2 + * ..NkR... 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") + void generateMovablePositions() { + Position position = new Position(Row.TWO, Column.D); + Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.TWO, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.ONE, Column.D), new Piece(PieceType.KING, Color.WHITE), + new Position(Row.THREE, Column.C), new Piece(PieceType.BLACK_PAWN, Color.WHITE), + new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.FOUR, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK), + new Position(Row.ONE, Column.E), new Piece(PieceType.ROOK, Color.BLACK), + new Position(Row.ONE, Column.C), new Piece(PieceType.KNIGHT, Color.BLACK), + new Position(Row.TWO, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK) + + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.THREE, Column.D), + new Position(Row.FOUR, Column.D), + new Position(Row.FIVE, Column.D), + new Position(Row.SIX, Column.D), + new Position(Row.SEVEN, Column.D), + new Position(Row.THREE, Column.E), + new Position(Row.FOUR, Column.F), + new Position(Row.ONE, Column.E), + new Position(Row.ONE, Column.C), + new Position(Row.TWO, Column.C) + ); + } +} diff --git a/src/test/java/chess/domain/positionFilter/RookTest.java b/src/test/java/chess/domain/positionFilter/RookTest.java new file mode 100644 index 00000000000..6dd24fea2fa --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/RookTest.java @@ -0,0 +1,58 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RookTest { + + /** + * ........ 8 (rank 8) + * ........ 7 + * ...B.... 6 + * .n.Rr... 5 + * ...r.... 4 + * ........ 3 + * ........ 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") + void generateMovablePositions() { + Position position = new Position(Row.FIVE, Column.D); + Piece piece = new Piece(PieceType.ROOK, Color.BLACK); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.FOUR, Column.D), new Piece(PieceType.ROOK, Color.WHITE), + new Position(Row.FIVE, Column.E), new Piece(PieceType.ROOK, Color.WHITE), + new Position(Row.FIVE, Column.B), new Piece(PieceType.KNIGHT, Color.WHITE), + new Position(Row.SIX, Column.D), new Piece(PieceType.BISHOP, Color.BLACK) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.FOUR, Column.D), + new Position(Row.FIVE, Column.E), + new Position(Row.FIVE, Column.B), + new Position(Row.FIVE, Column.C) + ); + } + +} diff --git a/src/test/java/chess/domain/positionFilter/WhitePawnTest.java b/src/test/java/chess/domain/positionFilter/WhitePawnTest.java new file mode 100644 index 00000000000..d94556ca33a --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/WhitePawnTest.java @@ -0,0 +1,118 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.Board; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class WhitePawnTest { + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ..R.R... 3 + * ...p.... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("화이트 폰 시작 위치에서 양쪽 대각선에 상대 기물이 있고 앞 2칸은 비어있다.") + void startPositionPawnWithOnlyAttackablePositions() { + Position position = new Position(Row.TWO, Column.D); + Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.THREE, Column.C), new Piece(PieceType.ROOK, Color.BLACK), + new Position(Row.THREE, Column.E), new Piece(PieceType.ROOK, Color.BLACK) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.THREE, Column.C), + new Position(Row.THREE, Column.E), + new Position(Row.THREE, Column.D), + new Position(Row.FOUR, Column.D) + ); + } + + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ..p..... 3 + * ...p.... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("화이트 폰 시작 위치에서 앞으로만 이동할 수 있는 경우") + void startPositionPawnWithFreePositions() { + Position position = new Position(Row.TWO, Column.D); + Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.THREE, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.THREE, Column.D), + new Position(Row.FOUR, Column.D) + ); + } + + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ..pP.... 3 + * ...p.... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("화이트 폰 시작 위치에서 움직일 수 없는 경우") + void startPositionPawnWithCantMovePositions() { + Position position = new Position(Row.TWO, Column.D); + Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); + Board board = new Board( + Map.of( + position, piece, + new Position(Row.THREE, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Position(Row.THREE, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK) + ) + ); + + List movablePositions = new PositionsFilter().generateValidPositions( + piece.generateAllDirectionPositions(position), piece, board); + + assertThat(movablePositions).isEmpty(); + } +} diff --git a/src/test/java/chess/domain/strategy/BishopMoveStrategyTest.java b/src/test/java/chess/domain/strategy/BishopMoveStrategyTest.java new file mode 100644 index 00000000000..28a0cab936e --- /dev/null +++ b/src/test/java/chess/domain/strategy/BishopMoveStrategyTest.java @@ -0,0 +1,88 @@ +package chess.domain.strategy; + +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class BishopMoveStrategyTest { + + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ........ 3 + * .b...... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("비숍이 B2 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnEdgePosition() { + Position position = new Position(Row.TWO, Column.B); + MoveStrategy moveStrategy = new BishopMoveStrategy(); + + Map> directionListMap = moveStrategy.generateMovablePositions(position); + + assertAll( + () -> Assertions.assertThat(directionListMap.get(Direction.NE)).containsExactly( + new Position(Row.THREE, Column.C), + new Position(Row.FOUR, Column.D), + new Position(Row.FIVE, Column.E), + new Position(Row.SIX, Column.F), + new Position(Row.SEVEN, Column.G), + new Position(Row.EIGHT, Column.H) + ), + () -> Assertions.assertThat(directionListMap.get(Direction.SE)).containsExactly( + new Position(Row.ONE, Column.C) + ), + () -> Assertions.assertThat(directionListMap.get(Direction.SW)).containsExactly( + new Position(Row.ONE, Column.A) + ), + () -> Assertions.assertThat(directionListMap.get(Direction.NW)).containsExactly( + new Position(Row.THREE, Column.A) + ) + ); + } + + /** + * ........ 8 (rank 8) ........ 7 ........ 6 ........ 5 ........ 4 ........ 3 ........ 2 ..b..... 1 (rank + * 1) + *

+ * abcdefgh + */ + @Test + @DisplayName("비숍이 C1 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnCenterPosition() { + Position position = new Position(Row.ONE, Column.C); + BishopMoveStrategy bishopMoveStrategy = new BishopMoveStrategy(); + + Map> directionListMap = bishopMoveStrategy.generateMovablePositions(position); + + assertAll( + () -> Assertions.assertThat(directionListMap.get(Direction.NE)).containsExactly( + new Position(Row.TWO, Column.D), + new Position(Row.THREE, Column.E), + new Position(Row.FOUR, Column.F), + new Position(Row.FIVE, Column.G), + new Position(Row.SIX, Column.H) + ), + () -> Assertions.assertThat(directionListMap.get(Direction.SE)).isEmpty(), + () -> Assertions.assertThat(directionListMap.get(Direction.SW)).isEmpty(), + () -> Assertions.assertThat(directionListMap.get(Direction.NW)).containsExactly( + new Position(Row.TWO, Column.B), + new Position(Row.THREE, Column.A) + ) + ); + } +} diff --git a/src/test/java/chess/domain/strategy/BlackPawnMoveStrategyTest.java b/src/test/java/chess/domain/strategy/BlackPawnMoveStrategyTest.java new file mode 100644 index 00000000000..2f84ceeaea5 --- /dev/null +++ b/src/test/java/chess/domain/strategy/BlackPawnMoveStrategyTest.java @@ -0,0 +1,70 @@ +package chess.domain.strategy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.piece.PieceType; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class BlackPawnMoveStrategyTest { + + /** + * ........ 8 (rank 8) + * ......P. 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ........ 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("블랙 폰은 시작 위치에서는 아래로 2칸을 움직일 수 있다.") + void canMoveTwoDistanceAtStartPositionTest() { + PieceType blackPawn = PieceType.BLACK_PAWN; + + Map> directionListMap = blackPawn.generateAllDirectionPositions( + new Position(Row.SEVEN, Column.G)); + + assertAll( + () -> assertThat(directionListMap.get(Direction.S)).containsExactly( + new Position(Row.SIX, Column.G), + new Position(Row.FIVE, Column.G)), + () -> assertThat(directionListMap.get(Direction.N)).isNull(), + () -> assertThat(directionListMap.get(Direction.E)).isNull(), + () -> assertThat(directionListMap.get(Direction.W)).isNull(), + () -> assertThat(directionListMap.get(Direction.SE)).containsExactly(new Position(Row.SIX, Column.H)), + () -> assertThat(directionListMap.get(Direction.SW)).containsExactly(new Position(Row.SIX, Column.F)) + ); + } + + /** + * ........ 8 (rank 8) ........ 7 .......P 6 ........ 5 ........ 4 ........ 3 ........ 2 ........ 1 (rank + * 1) + *

+ * abcdefgh + */ + @Test + @DisplayName("블랙 폰은 시작 위치가 아니면 아래로 1칸만 움직일 수 있다.") + void canMoveOneDistancePositionTest() { + PieceType blackPawn = PieceType.BLACK_PAWN; + + Map> directionListMap = blackPawn.generateAllDirectionPositions( + new Position(Row.SIX, Column.H)); + + assertAll( + () -> assertThat(directionListMap.get(Direction.S)).containsExactly( + new Position(Row.FIVE, Column.H) + )) + ; + } +} diff --git a/src/test/java/chess/domain/strategy/KingMoveStrategyTest.java b/src/test/java/chess/domain/strategy/KingMoveStrategyTest.java new file mode 100644 index 00000000000..e97cc2895f9 --- /dev/null +++ b/src/test/java/chess/domain/strategy/KingMoveStrategyTest.java @@ -0,0 +1,63 @@ +package chess.domain.strategy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class KingMoveStrategyTest { + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ...k.... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("킹이 D2 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnEdgePosition() { + Position position = new Position(Row.TWO, Column.D); + MoveStrategy moveStrategy = new KingMoveStrategy(); + + Map> directionListMap = moveStrategy.generateMovablePositions(position); + + assertAll( + () -> assertThat(directionListMap.get(Direction.N)).containsExactly( + new Position(Row.THREE, Column.D) + ), + () -> assertThat(directionListMap.get(Direction.NE)).containsExactly( + new Position(Row.THREE, Column.E) + ), + () -> assertThat(directionListMap.get(Direction.E)).containsExactly( + new Position(Row.TWO, Column.E) + ), + () -> assertThat(directionListMap.get(Direction.SE)).containsExactly( + new Position(Row.ONE, Column.E) + ), + () -> assertThat(directionListMap.get(Direction.S)).containsExactly( + new Position(Row.ONE, Column.D) + ), + () -> assertThat(directionListMap.get(Direction.SW)).containsExactly( + new Position(Row.ONE, Column.C) + ), + () -> assertThat(directionListMap.get(Direction.W)).containsExactly( + new Position(Row.TWO, Column.C) + ), + () -> assertThat(directionListMap.get(Direction.NW)).containsExactly( + new Position(Row.THREE, Column.C) + ) + ); + } +} diff --git a/src/test/java/chess/domain/strategy/KnightMoveStrategyTest.java b/src/test/java/chess/domain/strategy/KnightMoveStrategyTest.java new file mode 100644 index 00000000000..b514cb0523b --- /dev/null +++ b/src/test/java/chess/domain/strategy/KnightMoveStrategyTest.java @@ -0,0 +1,59 @@ +package chess.domain.strategy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class KnightMoveStrategyTest { + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ...n.... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("나이트가 D2 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnEdgePosition() { + Position position = new Position(Row.TWO, Column.D); + MoveStrategy moveStrategy = new KnightMoveStrategy(); + + Map> directionListMap = moveStrategy.generateMovablePositions(position); + + assertAll( + () -> assertThat(directionListMap.get(Direction.NNE)).containsExactly( + new Position(Row.FOUR, Column.E) + ), + () -> assertThat(directionListMap.get(Direction.ENE)).containsExactly( + new Position(Row.THREE, Column.F) + ), + () -> assertThat(directionListMap.get(Direction.ESE)).containsExactly( + new Position(Row.ONE, Column.F) + ), + () -> assertThat(directionListMap.get(Direction.SSE)).isEmpty(), + () -> assertThat(directionListMap.get(Direction.SSW)).isEmpty(), + () -> assertThat(directionListMap.get(Direction.WSW)).containsExactly( + new Position(Row.ONE, Column.B) + ), + () -> assertThat(directionListMap.get(Direction.WNW)).containsExactly( + new Position(Row.THREE, Column.B) + ), + () -> assertThat(directionListMap.get(Direction.NNW)).containsExactly( + new Position(Row.FOUR, Column.C) + ) + ); + } +} diff --git a/src/test/java/chess/domain/strategy/QueenMoveStrategyTest.java b/src/test/java/chess/domain/strategy/QueenMoveStrategyTest.java new file mode 100644 index 00000000000..453e59746db --- /dev/null +++ b/src/test/java/chess/domain/strategy/QueenMoveStrategyTest.java @@ -0,0 +1,79 @@ +package chess.domain.strategy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class QueenMoveStrategyTest { + + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ...q.... 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("퀸이 D2 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnEdgePosition() { + Position position = new Position(Row.TWO, Column.D); + MoveStrategy moveStrategy = new QueenMoveStrategy(); + + Map> directionListMap = moveStrategy.generateMovablePositions(position); + + assertAll( + () -> assertThat(directionListMap.get(Direction.N)).containsExactly( + new Position(Row.THREE, Column.D), + new Position(Row.FOUR, Column.D), + new Position(Row.FIVE, Column.D), + new Position(Row.SIX, Column.D), + new Position(Row.SEVEN, Column.D), + new Position(Row.EIGHT, Column.D) + ), + () -> assertThat(directionListMap.get(Direction.NE)).containsExactly( + new Position(Row.THREE, Column.E), + new Position(Row.FOUR, Column.F), + new Position(Row.FIVE, Column.G), + new Position(Row.SIX, Column.H) + ), + () -> assertThat(directionListMap.get(Direction.E)).containsExactly( + new Position(Row.TWO, Column.E), + new Position(Row.TWO, Column.F), + new Position(Row.TWO, Column.G), + new Position(Row.TWO, Column.H) + ), + () -> assertThat(directionListMap.get(Direction.SE)).containsExactly( + new Position(Row.ONE, Column.E) + ), + () -> assertThat(directionListMap.get(Direction.S)).containsExactly( + new Position(Row.ONE, Column.D) + ), + () -> assertThat(directionListMap.get(Direction.SW)).containsExactly( + new Position(Row.ONE, Column.C) + ), + () -> assertThat(directionListMap.get(Direction.W)).containsExactly( + new Position(Row.TWO, Column.C), + new Position(Row.TWO, Column.B), + new Position(Row.TWO, Column.A) + ), + () -> assertThat(directionListMap.get(Direction.NW)).containsExactly( + new Position(Row.THREE, Column.C), + new Position(Row.FOUR, Column.B), + new Position(Row.FIVE, Column.A) + ) + ); + } +} diff --git a/src/test/java/chess/domain/strategy/RookMoveStrategyTest.java b/src/test/java/chess/domain/strategy/RookMoveStrategyTest.java new file mode 100644 index 00000000000..6b96804180d --- /dev/null +++ b/src/test/java/chess/domain/strategy/RookMoveStrategyTest.java @@ -0,0 +1,85 @@ +package chess.domain.strategy; + +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RookMoveStrategyTest { + + @Test + @DisplayName("룩이 A1 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnEdgePosition() { + Position position = new Position(Row.ONE, Column.A); + MoveStrategy moveStrategy = new RookMoveStrategy(); + + Map> directionListMap = moveStrategy.generateMovablePositions(position); + + assertAll( + () -> Assertions.assertThat(directionListMap.get(Direction.N)).containsExactly( + new Position(Row.TWO, Column.A), + new Position(Row.THREE, Column.A), + new Position(Row.FOUR, Column.A), + new Position(Row.FIVE, Column.A), + new Position(Row.SIX, Column.A), + new Position(Row.SEVEN, Column.A), + new Position(Row.EIGHT, Column.A) + ), + () -> Assertions.assertThat(directionListMap.get(Direction.S)).isEmpty(), + () -> Assertions.assertThat(directionListMap.get(Direction.E)).containsExactly( + new Position(Row.ONE, Column.B), + new Position(Row.ONE, Column.C), + new Position(Row.ONE, Column.D), + new Position(Row.ONE, Column.E), + new Position(Row.ONE, Column.F), + new Position(Row.ONE, Column.G), + new Position(Row.ONE, Column.H) + + ), + () -> Assertions.assertThat(directionListMap.get(Direction.W)).isEmpty() + ); + } + + @Test + @DisplayName("룩이 D4 에 있을 때 방향에 따라 움직일 수 있는 후보 포지션을 차례대로 저장한다.") + void calculateCandidateOnCenterPosition() { + Position position = new Position(Row.FOUR, Column.D); + MoveStrategy moveStrategy = new RookMoveStrategy(); + + Map> directionListMap = moveStrategy.generateMovablePositions(position); + + assertAll( + () -> Assertions.assertThat(directionListMap.get(Direction.N)).containsExactly( + new Position(Row.FIVE, Column.D), + new Position(Row.SIX, Column.D), + new Position(Row.SEVEN, Column.D), + new Position(Row.EIGHT, Column.D) + ), + () -> Assertions.assertThat(directionListMap.get(Direction.E)).containsExactly( + new Position(Row.FOUR, Column.E), + new Position(Row.FOUR, Column.F), + new Position(Row.FOUR, Column.G), + new Position(Row.FOUR, Column.H) + + ), + () -> Assertions.assertThat(directionListMap.get(Direction.S)).containsExactly( + new Position(Row.THREE, Column.D), + new Position(Row.TWO, Column.D), + new Position(Row.ONE, Column.D) + ) + , + () -> Assertions.assertThat(directionListMap.get(Direction.W)).containsExactly( + new Position(Row.FOUR, Column.C), + new Position(Row.FOUR, Column.B), + new Position(Row.FOUR, Column.A) + ) + ); + } +} diff --git a/src/test/java/chess/domain/strategy/WhitePawnMoveStrategyTest.java b/src/test/java/chess/domain/strategy/WhitePawnMoveStrategyTest.java new file mode 100644 index 00000000000..2016034b19f --- /dev/null +++ b/src/test/java/chess/domain/strategy/WhitePawnMoveStrategyTest.java @@ -0,0 +1,76 @@ +package chess.domain.strategy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.piece.PieceType; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import java.util.Map; +import java.util.Queue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class WhitePawnMoveStrategyTest { + + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * ........ 3 + * ......p. 2 + * ........ 1 (rank 1) + * + * abcdefgh + */ + @Test + @DisplayName("화이트 폰은 시작 위치에서는 아래로 2칸을 움직일 수 있다.") + void canMoveTwoDistanceAtStartPositionTest() { + PieceType whitePawn = PieceType.WHITE_PAWN; + + Map> directionListMap = whitePawn.generateAllDirectionPositions( + new Position(Row.TWO, Column.G)); + + assertAll( + () -> assertThat(directionListMap.get(Direction.N)).containsExactly( + new Position(Row.THREE, Column.G), + new Position(Row.FOUR, Column.G)), + () -> assertThat(directionListMap.get(Direction.S)).isNull(), + () -> assertThat(directionListMap.get(Direction.E)).isNull(), + () -> assertThat(directionListMap.get(Direction.W)).isNull(), + () -> assertThat(directionListMap.get(Direction.NE)).containsExactly(new Position(Row.THREE, Column.H)), + () -> assertThat(directionListMap.get(Direction.NW)).containsExactly(new Position(Row.THREE, Column.F)) + ); + } + + /** + * ........ 8 (rank 8) + * ........ 7 + * ........ 6 + * ........ 5 + * ........ 4 + * .......p 3 + * ........ 2 + * ........ 1 (rank1) + * + * abcdefgh + */ + @Test + @DisplayName("화이트 폰은 시작 위치가 아니면 위로 1칸만 움직일 수 있다.") + void canMoveOneDistancePositionTest() { + PieceType whitePawn = PieceType.WHITE_PAWN; + + Map> directionListMap = whitePawn.generateAllDirectionPositions( + new Position(Row.THREE, Column.H)); + + assertAll( + () -> assertThat(directionListMap.get(Direction.N)).containsExactly( + new Position(Row.FOUR, Column.H) + ) + ); + } +} diff --git a/src/test/java/chess/view/mapper/ColumnMapperTest.java b/src/test/java/chess/view/mapper/ColumnMapperTest.java new file mode 100644 index 00000000000..115d5246499 --- /dev/null +++ b/src/test/java/chess/view/mapper/ColumnMapperTest.java @@ -0,0 +1,37 @@ +package chess.view.mapper; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import chess.domain.board.position.Column; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ColumnMapperTest { + + @Test + @DisplayName("이름으로 Column를 찾는다.") + void findByInputValueSuccessTest() { + assertAll( + () -> assertEquals(Column.A, ColumnMapper.findByInputValue("a")), + () -> assertEquals(Column.B, ColumnMapper.findByInputValue("b")), + () -> assertEquals(Column.C, ColumnMapper.findByInputValue("c")), + () -> assertEquals(Column.D, ColumnMapper.findByInputValue("d")), + () -> assertEquals(Column.E, ColumnMapper.findByInputValue("e")), + () -> assertEquals(Column.F, ColumnMapper.findByInputValue("f")), + () -> assertEquals(Column.G, ColumnMapper.findByInputValue("g")), + () -> assertEquals(Column.H, ColumnMapper.findByInputValue("h")) + ); + } + + @ParameterizedTest + @ValueSource(strings = {" ", "zxc", "123"}) + @DisplayName("이름으로 Column를 찾는데 실패한다.") + void findByInputValueFailTest(String value) { + assertThatThrownBy(() -> ColumnMapper.findByInputValue(value)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/chess/view/mapper/RowMapperTest.java b/src/test/java/chess/view/mapper/RowMapperTest.java new file mode 100644 index 00000000000..db6f60635ff --- /dev/null +++ b/src/test/java/chess/view/mapper/RowMapperTest.java @@ -0,0 +1,38 @@ +package chess.view.mapper; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import chess.domain.board.position.Row; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RowMapperTest { + + @Test + @DisplayName("이름으로 Row를 찾는다.") + void findByInputValueSuccessTest() { + assertAll( + () -> assertEquals(Row.ONE, RowMapper.findByInputValue("1")), + () -> assertEquals(Row.TWO, RowMapper.findByInputValue("2")), + () -> assertEquals(Row.THREE, RowMapper.findByInputValue("3")), + () -> assertEquals(Row.FOUR, RowMapper.findByInputValue("4")), + () -> assertEquals(Row.FIVE, RowMapper.findByInputValue("5")), + () -> assertEquals(Row.SIX, RowMapper.findByInputValue("6")), + () -> assertEquals(Row.SEVEN, RowMapper.findByInputValue("7")), + () -> assertEquals(Row.EIGHT, RowMapper.findByInputValue("8")) + ); + } + + @ParameterizedTest + @ValueSource(strings = {" ", "zxc", "123"}) + @DisplayName("이름으로 Row를 찾는데 실패한다.") + void findByInputValueFailTest(String value) { + assertThatThrownBy(() -> RowMapper.findByInputValue(value)) + .isInstanceOf(IllegalArgumentException.class); + } + +} From 44befb220671793da068ce985295323d9a0d2a3b Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Wed, 27 Mar 2024 11:21:42 +0900 Subject: [PATCH 02/18] =?UTF-8?q?refactor(Board):=20equals=20&=20hashcode?= =?UTF-8?q?=20=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EC=B4=88=EA=B8=B0=ED=99=94=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/domain/board/Board.java | 18 --- .../java/chess/domain/board/BoardTest.java | 113 +++++++++++------- 2 files changed, 67 insertions(+), 64 deletions(-) diff --git a/src/main/java/chess/domain/board/Board.java b/src/main/java/chess/domain/board/Board.java index 18b73c41cbc..d2c650e95eb 100644 --- a/src/main/java/chess/domain/board/Board.java +++ b/src/main/java/chess/domain/board/Board.java @@ -4,7 +4,6 @@ import chess.domain.piece.Piece; import java.util.HashMap; import java.util.Map; -import java.util.Objects; public class Board { @@ -48,21 +47,4 @@ public Map getBoard() { void put(Position position, Piece piece) { board.put(position, piece); } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Board other = (Board) o; - return Objects.equals(board, other.board); - } - - @Override - public int hashCode() { - return Objects.hash(board); - } } diff --git a/src/test/java/chess/domain/board/BoardTest.java b/src/test/java/chess/domain/board/BoardTest.java index 00354f990e1..8f3b2cc52a6 100644 --- a/src/test/java/chess/domain/board/BoardTest.java +++ b/src/test/java/chess/domain/board/BoardTest.java @@ -1,6 +1,8 @@ package chess.domain.board; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; import chess.domain.board.position.Column; import chess.domain.board.position.Position; @@ -8,65 +10,84 @@ import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; -import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; class BoardTest { - @Test - @DisplayName("보드 생성 시 32개의 기물이 초기화된다.") - void printMap() { - Board board = new Board(); - - Map boardMap = board.getBoard(); + private Map map; - assertThat(boardMap).hasSize(32); + @BeforeEach + void setUp() { + map = new Board().getBoard(); } @Test - @DisplayName("보드 팩토리로 체스 시작 보드가 정상적으로 초기화 된다") - void boardInitializeTest() { - Map map = new HashMap<>(); - map.put(new Position(Row.ONE, Column.A), new Piece(PieceType.ROOK, Color.WHITE)); - map.put(new Position(Row.ONE, Column.H), new Piece(PieceType.ROOK, Color.WHITE)); - map.put(new Position(Row.ONE, Column.B), new Piece(PieceType.KNIGHT, Color.WHITE)); - map.put(new Position(Row.ONE, Column.G), new Piece(PieceType.KNIGHT, Color.WHITE)); - map.put(new Position(Row.ONE, Column.C), new Piece(PieceType.BISHOP, Color.WHITE)); - map.put(new Position(Row.ONE, Column.F), new Piece(PieceType.BISHOP, Color.WHITE)); - map.put(new Position(Row.ONE, Column.D), new Piece(PieceType.QUEEN, Color.WHITE)); - map.put(new Position(Row.ONE, Column.E), new Piece(PieceType.KING, Color.WHITE)); - - map.put(new Position(Row.TWO, Column.A), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.H), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.G), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.F), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.D), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + @DisplayName("보드 생성 시 32개의 기물이 초기화된다.") + void printMap() { + assertThat(map).hasSize(32); + } - map.put(new Position(Row.EIGHT, Column.A), new Piece(PieceType.ROOK, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.H), new Piece(PieceType.ROOK, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.B), new Piece(PieceType.KNIGHT, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.G), new Piece(PieceType.KNIGHT, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.C), new Piece(PieceType.BISHOP, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.F), new Piece(PieceType.BISHOP, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.D), new Piece(PieceType.QUEEN, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.E), new Piece(PieceType.KING, Color.BLACK)); + @Nested + @DisplayName("체스 보드 초기화 정상 테스트") + class BoardInitializeTest { + @Test + @DisplayName("검정 폰이 정상적으로 초기화된다.") + void blackPawnInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.A)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.H)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.B)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.G)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.C)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.F)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.D)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.E)), new Piece(PieceType.BLACK_PAWN, Color.BLACK))); + } - map.put(new Position(Row.SEVEN, Column.A), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.H), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.B), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.G), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + @Test + @DisplayName("흰색 폰이 정상적으로 초기화된다.") + void whitePawnInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.TWO, Column.A)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.H)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.B)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.G)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.C)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.F)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.D)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.E)), new Piece(PieceType.WHITE_PAWN, Color.WHITE))); + } - Board board = new Board(); + @Test + @DisplayName("폰을 제외한 검정 기물들이 정상적으로 초기화된다.") + void blackSpecialPieceInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.A)), new Piece(PieceType.ROOK, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.H)), new Piece(PieceType.ROOK, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.B)), new Piece(PieceType.KNIGHT, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.G)), new Piece(PieceType.KNIGHT, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.C)), new Piece(PieceType.BISHOP, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.F)), new Piece(PieceType.BISHOP, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.D)), new Piece(PieceType.QUEEN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.E)), new Piece(PieceType.KING, Color.BLACK))); + } - assertThat(new Board(map)).isEqualTo(board); + @Test + @DisplayName("폰을 제외 흰색 기물들이 정상적으로 초기화된다.") + void whiteSpecialPieceInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.ONE, Column.A)), new Piece(PieceType.ROOK, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.H)), new Piece(PieceType.ROOK, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.B)), new Piece(PieceType.KNIGHT, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.G)), new Piece(PieceType.KNIGHT, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.C)), new Piece(PieceType.BISHOP, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.F)), new Piece(PieceType.BISHOP, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.D)), new Piece(PieceType.QUEEN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.E)), new Piece(PieceType.KING, Color.WHITE))); + } } } From 67070eda753781c91ea146793af4888c319cda9d Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Wed, 27 Mar 2024 20:14:36 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat(Board):=20=EA=B0=81=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=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../chess/controller/ChessGameController.java | 30 ++++++++++++--- src/main/java/chess/domain/board/Board.java | 38 +++++++++++++++++++ .../chess/domain/board/position/Position.java | 4 ++ .../java/chess/domain/game/ChessGame.java | 4 ++ src/main/java/chess/domain/piece/Piece.java | 19 ++++++++-- .../java/chess/domain/piece/PieceType.java | 30 +++++++++++---- src/main/java/chess/view/Command.java | 5 ++- src/main/java/chess/view/InputView.java | 2 +- src/main/java/chess/view/OutputView.java | 23 +++++------ .../java/chess/view/mapper/PieceMapper.java | 3 +- .../java/chess/domain/board/BoardTest.java | 33 ++++++++++++++++ 12 files changed, 160 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 9117e93cf5f..9695d995e70 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - [X] : start, end 가 아니면 예외를 터트린다. - [X] : start 입력 시 게임을 시작한다. - [X] : end 입력 시 게임을 종료한다. -- + - [ ] : status 입력 시 각 팀의 점수와 어느 팀이 우세한지 출력한다 - [X] : 보드판을 초기화한다. - [X] : 소문자, 대문자로 팀을 구분한다. - [X] : 각 팀은 총 16개의 말을 갖는다. diff --git a/src/main/java/chess/controller/ChessGameController.java b/src/main/java/chess/controller/ChessGameController.java index 7f16edb769c..f3d5f6982e8 100644 --- a/src/main/java/chess/controller/ChessGameController.java +++ b/src/main/java/chess/controller/ChessGameController.java @@ -5,12 +5,14 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.ChessGame; +import chess.domain.piece.Color; import chess.view.Command; import chess.view.InputView; import chess.view.MoveRequestDto; import chess.view.OutputView; import chess.view.mapper.ColumnMapper; import chess.view.mapper.RowMapper; +import java.util.Map; public class ChessGameController { private final InputView inputView = new InputView(); @@ -32,12 +34,9 @@ private void process(ChessGame chessGame) { private boolean processGame(ChessGame chessGame) { try { Command command = inputView.readCommend(); - if (command == Command.START) { - handleStart(chessGame); - } - if (command == Command.MOVE) { - handleMove(chessGame); - } + processGameStart(chessGame, command); + processMove(chessGame, command); + processStatus(chessGame, command); return command != Command.END; } catch (IllegalArgumentException error) { outputView.printError(error); @@ -46,6 +45,25 @@ private boolean processGame(ChessGame chessGame) { } } + private void processStatus(ChessGame chessGame, Command command) { + if (command == Command.STATUS) { + Map teamScore = chessGame.calculateTeamScore(); + outputView.printTeamScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); + } + } + + private void processMove(ChessGame chessGame, Command command) { + if (command == Command.MOVE) { + handleMove(chessGame); + } + } + + private void processGameStart(ChessGame chessGame, Command command) { + if (command == Command.START) { + handleStart(chessGame); + } + } + private void handleStart(ChessGame chessGame) { outputView.printBoard(chessGame.getBoard()); } diff --git a/src/main/java/chess/domain/board/Board.java b/src/main/java/chess/domain/board/Board.java index d2c650e95eb..392703cfc89 100644 --- a/src/main/java/chess/domain/board/Board.java +++ b/src/main/java/chess/domain/board/Board.java @@ -1,9 +1,13 @@ package chess.domain.board; +import chess.domain.board.position.Column; import chess.domain.board.position.Position; +import chess.domain.piece.Color; import chess.domain.piece.Piece; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; public class Board { @@ -19,6 +23,40 @@ public Board(Map board) { this.board = board; } + public Map calculateScore() { + return Arrays.stream(Color.values()).collect(Collectors.toMap( + color -> color, + this::calculateTotalScore + )); + } + + private double calculateTotalScore(Color color) { + double sum = sumTotalScore(color); + double pawnMinus = calculatePawnScore(color); + return sum - pawnMinus; + } + + private double sumTotalScore(Color color) { + return board.values().stream() + .filter(piece -> piece.isSameColor(color)) + .mapToDouble(Piece::getScore) + .sum(); + } + + private Map countPawnByColumn(Color color) { + return board.keySet().stream() + .filter(position -> board.get(position).isPawnByColor(color)) + .collect(Collectors.groupingBy(Position::getColumn, Collectors.counting())); + } + + private double calculatePawnScore(Color color) { + Map pawnCountByColumn = countPawnByColumn(color); + return pawnCountByColumn.values().stream() + .filter(pawnCount -> pawnCount >= 2) + .mapToDouble(pawnCount -> pawnCount * 0.5) + .sum(); + } + public void movePiece(Position from, Position to) { Piece piece = board.get(from); board.put(to, piece); diff --git a/src/main/java/chess/domain/board/position/Position.java b/src/main/java/chess/domain/board/position/Position.java index 96be2b7a6f3..3174e85b979 100644 --- a/src/main/java/chess/domain/board/position/Position.java +++ b/src/main/java/chess/domain/board/position/Position.java @@ -48,6 +48,10 @@ public int getColumnIndex() { return column.getIndex(); } + public Column getColumn() { + return column; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index d0ae16e92b5..6cd59f64c28 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -21,6 +21,10 @@ public ChessGame(Board board) { currentTurn = START_TURN; } + public Map calculateTeamScore() { + return board.calculateScore(); + } + public void movePiece(Position from, Position to) { validateUserTurn(from); List movablePositions = generateMovablePositions(from); diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index 82a512f67a2..8fe46876cca 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -24,12 +24,23 @@ public boolean isEnemy(Piece piece) { return isNotSameColor(piece.color); } - public boolean isBlack() { - return this.color == Color.BLACK; + public boolean isSameColor(Color color) { + return this.color == color; } - public boolean isNotSameColor(Color turn) { - return this.color != turn; + public boolean isNotSameColor(Color color) { + return !isSameColor(color); + } + + public boolean isPawnByColor(Color color) { + if (color == Color.BLACK) { + return pieceType.isBlackPawn(); + } + return pieceType.isWhitePawn(); + } + + public double getScore() { + return pieceType.getScore(); } public boolean isPawnAttackPossible(Direction direction) { diff --git a/src/main/java/chess/domain/piece/PieceType.java b/src/main/java/chess/domain/piece/PieceType.java index 8c60b98132a..277f245774c 100644 --- a/src/main/java/chess/domain/piece/PieceType.java +++ b/src/main/java/chess/domain/piece/PieceType.java @@ -14,21 +14,35 @@ import java.util.Queue; public enum PieceType { - BLACK_PAWN(new BlackPawnMoveStrategy()), - WHITE_PAWN(new WhitePawnMoveStrategy()), - ROOK(new RookMoveStrategy()), - KNIGHT(new KnightMoveStrategy()), - BISHOP(new BishopMoveStrategy()), - QUEEN(new QueenMoveStrategy()), - KING(new KingMoveStrategy()); + BLACK_PAWN(new BlackPawnMoveStrategy(), 1), + WHITE_PAWN(new WhitePawnMoveStrategy(), 1), + ROOK(new RookMoveStrategy(), 5), + KNIGHT(new KnightMoveStrategy(), 2.5), + BISHOP(new BishopMoveStrategy(), 3), + QUEEN(new QueenMoveStrategy(), 9), + KING(new KingMoveStrategy(), 0); private final MoveStrategy moveStrategy; + private final double score; - PieceType(MoveStrategy moveStrategy) { + PieceType(MoveStrategy moveStrategy, double score) { this.moveStrategy = moveStrategy; + this.score = score; } public Map> generateAllDirectionPositions(Position currentPosition) { return this.moveStrategy.generateMovablePositions(currentPosition); } + + public double getScore() { + return score; + } + + public boolean isBlackPawn() { + return this == BLACK_PAWN; + } + + public boolean isWhitePawn() { + return this == WHITE_PAWN; + } } diff --git a/src/main/java/chess/view/Command.java b/src/main/java/chess/view/Command.java index 32b8c8a9a5e..c3f4c39cf58 100644 --- a/src/main/java/chess/view/Command.java +++ b/src/main/java/chess/view/Command.java @@ -3,7 +3,10 @@ import java.util.Arrays; public enum Command { - START("start"), END("end"), MOVE("move"); + START("start"), + END("end"), + MOVE("move"), + STATUS("status"); private final String value; diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java index 12124e22731..37125458163 100644 --- a/src/main/java/chess/view/InputView.java +++ b/src/main/java/chess/view/InputView.java @@ -5,7 +5,7 @@ public class InputView { - private static final Pattern COMMAND_REGEX = Pattern.compile("(move)|(start)|(end)"); + private static final Pattern COMMAND_REGEX = Pattern.compile("(move)|(start)|(end)|(status)"); private static final Pattern POSITION_REGEX = Pattern.compile("([a-h][1-8]\\s+[a-h][1-8])"); private final Scanner scanner = new Scanner(System.in); diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index 6871626313e..d539839939c 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -1,14 +1,14 @@ package chess.view; -import chess.domain.piece.Piece; import chess.domain.board.Board; +import chess.domain.piece.Piece; import chess.view.mapper.PieceMapper; import java.util.ArrayList; import java.util.List; public class OutputView { - private static final String EMPTY_BOARD = "........"; + private static final String EMPTY_BOARD = ". . . . . . . ."; public void printStartMessage() { System.out.println("체스 게임을 시작합니다."); @@ -19,27 +19,28 @@ public void printStartMessage() { public void printBoard(Board board) { List result = new ArrayList<>(); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); - result.add(new StringBuilder(EMPTY_BOARD)); + for (int i = 0; i < 8; i++) { + result.add(new StringBuilder(EMPTY_BOARD)); + } board.getBoard().keySet() .forEach(position -> { Piece piece = board.getBoard().get(position); int rowIndex = position.getRowIndex(); int columnIndex = position.getColumnIndex(); - result.get(rowIndex).replace(columnIndex, columnIndex + 1, PieceMapper.findByPieceType(piece)); + result.get(rowIndex).replace(columnIndex * 2, columnIndex * 2 + 1, PieceMapper.findByPieceType(piece)); }); result.forEach(System.out::println); System.out.println(); } + public void printTeamScore(double whiteTeamScore, double blackTeamScore) { + System.out.println("---현재 점수---"); + System.out.println("흰색 팀: " + whiteTeamScore); + System.out.println("검정 팀: " + blackTeamScore); + } + public void printError(Exception exception) { System.out.println(exception.getMessage()); } diff --git a/src/main/java/chess/view/mapper/PieceMapper.java b/src/main/java/chess/view/mapper/PieceMapper.java index fa00ae8d847..c923c3b3baa 100644 --- a/src/main/java/chess/view/mapper/PieceMapper.java +++ b/src/main/java/chess/view/mapper/PieceMapper.java @@ -1,5 +1,6 @@ package chess.view.mapper; +import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.Arrays; @@ -28,7 +29,7 @@ public static String findByPieceType(Piece piece) { .findAny() .orElseThrow(() -> new IllegalArgumentException("일치하는 기물이 없습니다.")) .value; - if (piece.isBlack()) { + if (piece.isSameColor(Color.BLACK)) { return value.toUpperCase(); } return value; diff --git a/src/test/java/chess/domain/board/BoardTest.java b/src/test/java/chess/domain/board/BoardTest.java index 8f3b2cc52a6..afe17b36b9c 100644 --- a/src/test/java/chess/domain/board/BoardTest.java +++ b/src/test/java/chess/domain/board/BoardTest.java @@ -10,6 +10,7 @@ import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -90,4 +91,36 @@ void whiteSpecialPieceInitializeTest() { () -> assertEquals(map.get(new Position(Row.ONE, Column.E)), new Piece(PieceType.KING, Color.WHITE))); } } + + @Nested + @DisplayName("기물 점수 계산 테스트") + class CalculateScoreTest { + + @Test + void calculateTeamScoreTest() { + Map map = new HashMap<>(); + + map.put(new Position(Row.ONE, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.TWO, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.THREE, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + map.put(new Position(Row.ONE, Column.D), new Piece(PieceType.QUEEN, Color.WHITE)); + map.put(new Position(Row.ONE, Column.E), new Piece(PieceType.KING, Color.WHITE)); + map.put(new Position(Row.TWO, Column.F), new Piece(PieceType.ROOK, Color.WHITE)); + + map.put(new Position(Row.EIGHT, Column.G), new Piece(PieceType.KNIGHT, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.F), new Piece(PieceType.BISHOP, Color.BLACK)); + map.put(new Position(Row.EIGHT, Column.E), new Piece(PieceType.KING, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + map.put(new Position(Row.SEVEN, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); + + Board board = new Board(map); + Map scoreOfTeam = board.calculateScore(); + + assertAll( + () -> assertEquals(scoreOfTeam.get(Color.WHITE), 15.5), + () -> assertEquals(scoreOfTeam.get(Color.BLACK), 8.5) + ); + } + } } From 42cfa33f7d3db7f1b42dc67e19d43adf991e61c1 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 29 Mar 2024 19:01:31 +0900 Subject: [PATCH 04/18] =?UTF-8?q?refactor(BoardFactory):=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=B4=20map=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/domain/board/Board.java | 18 ++-- .../java/chess/domain/board/BoardFactory.java | 52 ++++++----- .../chess/domain/board/BoardFactoryTest.java | 93 +++++++++++++++++++ .../java/chess/domain/board/BoardTest.java | 82 +--------------- 4 files changed, 131 insertions(+), 114 deletions(-) create mode 100644 src/test/java/chess/domain/board/BoardFactoryTest.java diff --git a/src/main/java/chess/domain/board/Board.java b/src/main/java/chess/domain/board/Board.java index 392703cfc89..2255dea199e 100644 --- a/src/main/java/chess/domain/board/Board.java +++ b/src/main/java/chess/domain/board/Board.java @@ -2,10 +2,10 @@ import chess.domain.board.position.Column; import chess.domain.board.position.Position; +import chess.domain.game.Score; import chess.domain.piece.Color; import chess.domain.piece.Piece; import java.util.Arrays; -import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; @@ -13,27 +13,21 @@ public class Board { private final Map board; - public Board() { - this.board = new HashMap<>(); - BoardFactory boardFactory = new BoardFactory(); - boardFactory.initialize(this); - } - public Board(Map board) { this.board = board; } - public Map calculateScore() { + public Map calculateScore() { return Arrays.stream(Color.values()).collect(Collectors.toMap( color -> color, this::calculateTotalScore )); } - private double calculateTotalScore(Color color) { + private Score calculateTotalScore(Color color) { double sum = sumTotalScore(color); double pawnMinus = calculatePawnScore(color); - return sum - pawnMinus; + return new Score(sum - pawnMinus); } private double sumTotalScore(Color color) { @@ -58,8 +52,8 @@ private double calculatePawnScore(Color color) { } public void movePiece(Position from, Position to) { - Piece piece = board.get(from); - board.put(to, piece); + Piece fromPiece = board.get(from); + board.put(to, fromPiece); board.remove(from); } diff --git a/src/main/java/chess/domain/board/BoardFactory.java b/src/main/java/chess/domain/board/BoardFactory.java index d9fe47d17d7..3b0414f40dc 100644 --- a/src/main/java/chess/domain/board/BoardFactory.java +++ b/src/main/java/chess/domain/board/BoardFactory.java @@ -1,52 +1,56 @@ package chess.domain.board; -import chess.domain.piece.Color; import chess.domain.board.position.Column; -import chess.domain.piece.Piece; -import chess.domain.piece.PieceType; import chess.domain.board.position.Position; import chess.domain.board.position.Row; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.HashMap; +import java.util.Map; public class BoardFactory { - void initialize(Board board) { - initializeBlackTeam(board); - initializeWhiteTeam(board); + public Map initialize() { + Map map = new HashMap<>(); + initializeBlackTeam(map); + initializeWhiteTeam(map); + return map; } - private void initializeBlackTeam(Board board) { - initializePawn(board, Row.SEVEN, Color.BLACK); - initializeHighValuePiece(board, Row.EIGHT, Color.BLACK); + private void initializeBlackTeam(Map map) { + initializePawn(map, Row.SEVEN, Color.BLACK); + initializeHighValuePiece(map, Row.EIGHT, Color.BLACK); } - private void initializeWhiteTeam(Board board) { - initializePawn(board, Row.TWO, Color.WHITE); - initializeHighValuePiece(board, Row.ONE, Color.WHITE); + private void initializeWhiteTeam(Map map) { + initializePawn(map, Row.TWO, Color.WHITE); + initializeHighValuePiece(map, Row.ONE, Color.WHITE); } - private void initializePawn(Board board, Row row, Color color) { + private void initializePawn(Map map, Row row, Color color) { for (Column column : Column.values()) { Position position = new Position(row, column); if (color == Color.WHITE) { - board.put(position, new Piece(PieceType.WHITE_PAWN, color)); + map.put(position, new Piece(PieceType.WHITE_PAWN, color)); } if (color == Color.BLACK) { - board.put(position, new Piece(PieceType.BLACK_PAWN, color)); + map.put(position, new Piece(PieceType.BLACK_PAWN, color)); } } } - private void initializeHighValuePiece(Board board, Row row, Color color) { - board.put(new Position(row, Column.A), new Piece(PieceType.ROOK, color)); - board.put(new Position(row, Column.H), new Piece(PieceType.ROOK, color)); + private void initializeHighValuePiece(Map map, Row row, Color color) { + map.put(new Position(row, Column.A), new Piece(PieceType.ROOK, color)); + map.put(new Position(row, Column.H), new Piece(PieceType.ROOK, color)); - board.put(new Position(row, Column.B), new Piece(PieceType.KNIGHT, color)); - board.put(new Position(row, Column.G), new Piece(PieceType.KNIGHT, color)); + map.put(new Position(row, Column.B), new Piece(PieceType.KNIGHT, color)); + map.put(new Position(row, Column.G), new Piece(PieceType.KNIGHT, color)); - board.put(new Position(row, Column.C), new Piece(PieceType.BISHOP, color)); - board.put(new Position(row, Column.F), new Piece(PieceType.BISHOP, color)); + map.put(new Position(row, Column.C), new Piece(PieceType.BISHOP, color)); + map.put(new Position(row, Column.F), new Piece(PieceType.BISHOP, color)); - board.put(new Position(row, Column.D), new Piece(PieceType.QUEEN, color)); - board.put(new Position(row, Column.E), new Piece(PieceType.KING, color)); + map.put(new Position(row, Column.D), new Piece(PieceType.QUEEN, color)); + map.put(new Position(row, Column.E), new Piece(PieceType.KING, color)); } } diff --git a/src/test/java/chess/domain/board/BoardFactoryTest.java b/src/test/java/chess/domain/board/BoardFactoryTest.java new file mode 100644 index 00000000000..0363d33aa10 --- /dev/null +++ b/src/test/java/chess/domain/board/BoardFactoryTest.java @@ -0,0 +1,93 @@ +package chess.domain.board; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class BoardFactoryTest { + + private Map map; + + @BeforeEach + void setUp() { + map = new BoardFactory().initialize(); + } + + @Test + @DisplayName("보드 생성 시 32개의 기물이 초기화된다.") + void mapSizeTest() { + assertThat(map).hasSize(32); + } + + @Nested + @DisplayName("체스 보드 초기화 정상 테스트") + class BoardInitializeTest { + @Test + @DisplayName("검정 폰이 정상적으로 초기화된다.") + void blackPawnInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.A)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.H)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.B)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.G)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.C)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.F)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.D)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.SEVEN, Column.E)), new Piece(PieceType.BLACK_PAWN, Color.BLACK))); + } + + @Test + @DisplayName("흰색 폰이 정상적으로 초기화된다.") + void whitePawnInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.TWO, Column.A)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.H)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.B)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.G)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.C)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.F)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.D)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.TWO, Column.E)), new Piece(PieceType.WHITE_PAWN, Color.WHITE))); + } + + @Test + @DisplayName("폰을 제외한 검정 기물들이 정상적으로 초기화된다.") + void blackSpecialPieceInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.A)), new Piece(PieceType.ROOK, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.H)), new Piece(PieceType.ROOK, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.B)), new Piece(PieceType.KNIGHT, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.G)), new Piece(PieceType.KNIGHT, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.C)), new Piece(PieceType.BISHOP, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.F)), new Piece(PieceType.BISHOP, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.D)), new Piece(PieceType.QUEEN, Color.BLACK)), + () -> assertEquals(map.get(new Position(Row.EIGHT, Column.E)), new Piece(PieceType.KING, Color.BLACK))); + } + + @Test + @DisplayName("폰을 제외 흰색 기물들이 정상적으로 초기화된다.") + void whiteSpecialPieceInitializeTest() { + assertAll( + () -> assertEquals(map.get(new Position(Row.ONE, Column.A)), new Piece(PieceType.ROOK, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.H)), new Piece(PieceType.ROOK, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.B)), new Piece(PieceType.KNIGHT, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.G)), new Piece(PieceType.KNIGHT, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.C)), new Piece(PieceType.BISHOP, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.F)), new Piece(PieceType.BISHOP, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.D)), new Piece(PieceType.QUEEN, Color.WHITE)), + () -> assertEquals(map.get(new Position(Row.ONE, Column.E)), new Piece(PieceType.KING, Color.WHITE))); + } + } +} diff --git a/src/test/java/chess/domain/board/BoardTest.java b/src/test/java/chess/domain/board/BoardTest.java index afe17b36b9c..16571ae1c2d 100644 --- a/src/test/java/chess/domain/board/BoardTest.java +++ b/src/test/java/chess/domain/board/BoardTest.java @@ -1,97 +1,23 @@ package chess.domain.board; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import chess.domain.board.position.Column; import chess.domain.board.position.Position; import chess.domain.board.position.Row; +import chess.domain.game.Score; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.HashMap; import java.util.Map; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; class BoardTest { - private Map map; - - @BeforeEach - void setUp() { - map = new Board().getBoard(); - } - - @Test - @DisplayName("보드 생성 시 32개의 기물이 초기화된다.") - void printMap() { - assertThat(map).hasSize(32); - } - - @Nested - @DisplayName("체스 보드 초기화 정상 테스트") - class BoardInitializeTest { - @Test - @DisplayName("검정 폰이 정상적으로 초기화된다.") - void blackPawnInitializeTest() { - assertAll( - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.A)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.H)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.B)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.G)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.C)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.F)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.D)), new Piece(PieceType.BLACK_PAWN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.SEVEN, Column.E)), new Piece(PieceType.BLACK_PAWN, Color.BLACK))); - } - - @Test - @DisplayName("흰색 폰이 정상적으로 초기화된다.") - void whitePawnInitializeTest() { - assertAll( - () -> assertEquals(map.get(new Position(Row.TWO, Column.A)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.H)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.B)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.G)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.C)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.F)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.D)), new Piece(PieceType.WHITE_PAWN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.TWO, Column.E)), new Piece(PieceType.WHITE_PAWN, Color.WHITE))); - } - - @Test - @DisplayName("폰을 제외한 검정 기물들이 정상적으로 초기화된다.") - void blackSpecialPieceInitializeTest() { - assertAll( - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.A)), new Piece(PieceType.ROOK, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.H)), new Piece(PieceType.ROOK, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.B)), new Piece(PieceType.KNIGHT, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.G)), new Piece(PieceType.KNIGHT, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.C)), new Piece(PieceType.BISHOP, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.F)), new Piece(PieceType.BISHOP, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.D)), new Piece(PieceType.QUEEN, Color.BLACK)), - () -> assertEquals(map.get(new Position(Row.EIGHT, Column.E)), new Piece(PieceType.KING, Color.BLACK))); - } - - @Test - @DisplayName("폰을 제외 흰색 기물들이 정상적으로 초기화된다.") - void whiteSpecialPieceInitializeTest() { - assertAll( - () -> assertEquals(map.get(new Position(Row.ONE, Column.A)), new Piece(PieceType.ROOK, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.H)), new Piece(PieceType.ROOK, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.B)), new Piece(PieceType.KNIGHT, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.G)), new Piece(PieceType.KNIGHT, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.C)), new Piece(PieceType.BISHOP, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.F)), new Piece(PieceType.BISHOP, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.D)), new Piece(PieceType.QUEEN, Color.WHITE)), - () -> assertEquals(map.get(new Position(Row.ONE, Column.E)), new Piece(PieceType.KING, Color.WHITE))); - } - } - @Nested @DisplayName("기물 점수 계산 테스트") class CalculateScoreTest { @@ -115,11 +41,11 @@ void calculateTeamScoreTest() { map.put(new Position(Row.SEVEN, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); Board board = new Board(map); - Map scoreOfTeam = board.calculateScore(); + Map scoreOfTeam = board.calculateScore(); assertAll( - () -> assertEquals(scoreOfTeam.get(Color.WHITE), 15.5), - () -> assertEquals(scoreOfTeam.get(Color.BLACK), 8.5) + () -> assertEquals(scoreOfTeam.get(Color.WHITE), new Score(15.5)), + () -> assertEquals(scoreOfTeam.get(Color.BLACK), new Score(8.5)) ); } } From 3cf27805e4f3aabe323f7415f9d0cd220d73a324 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 29 Mar 2024 20:51:09 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=A0=90?= =?UTF-8?q?=EC=88=98=EB=A5=BC=20=EA=B3=84=EC=82=B0=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/controller/State.java | 7 ++ .../chess/controller/command/Command.java | 9 +++ .../controller/command/CommandRouter.java | 34 ++++++++++ .../java/chess/controller/command/End.java | 21 ++++++ .../java/chess/controller/command/Move.java | 60 ++++++++++++++++ .../java/chess/controller/command/Start.java | 23 +++++++ .../java/chess/controller/command/Status.java | 27 ++++++++ src/main/java/chess/domain/board/Board.java | 12 ++-- .../java/chess/domain/game/ChessGame.java | 20 +++++- .../chess/domain/game/ChessGameResult.java | 23 +++++++ src/main/java/chess/domain/game/Score.java | 38 +++++++++++ src/main/java/chess/domain/game/Winner.java | 33 +++++++++ src/main/java/chess/domain/piece/Piece.java | 8 +++ src/main/java/chess/view/Command.java | 26 ------- src/main/java/chess/view/OutputView.java | 44 +++++++++--- .../controller/command/CommandRouterTest.java | 59 ++++++++++++++++ .../chess/controller/command/EndTest.java | 40 +++++++++++ .../chess/controller/command/MoveTest.java | 40 +++++++++++ .../chess/controller/command/StartTest.java | 41 +++++++++++ .../chess/controller/command/StatusTest.java | 41 +++++++++++ .../java/chess/domain/game/WinnerTest.java | 68 +++++++++++++++++++ 21 files changed, 633 insertions(+), 41 deletions(-) create mode 100644 src/main/java/chess/controller/State.java create mode 100644 src/main/java/chess/controller/command/Command.java create mode 100644 src/main/java/chess/controller/command/CommandRouter.java create mode 100644 src/main/java/chess/controller/command/End.java create mode 100644 src/main/java/chess/controller/command/Move.java create mode 100644 src/main/java/chess/controller/command/Start.java create mode 100644 src/main/java/chess/controller/command/Status.java create mode 100644 src/main/java/chess/domain/game/ChessGameResult.java create mode 100644 src/main/java/chess/domain/game/Score.java create mode 100644 src/main/java/chess/domain/game/Winner.java delete mode 100644 src/main/java/chess/view/Command.java create mode 100644 src/test/java/chess/controller/command/CommandRouterTest.java create mode 100644 src/test/java/chess/controller/command/EndTest.java create mode 100644 src/test/java/chess/controller/command/MoveTest.java create mode 100644 src/test/java/chess/controller/command/StartTest.java create mode 100644 src/test/java/chess/controller/command/StatusTest.java create mode 100644 src/test/java/chess/domain/game/WinnerTest.java diff --git a/src/main/java/chess/controller/State.java b/src/main/java/chess/controller/State.java new file mode 100644 index 00000000000..c510850380a --- /dev/null +++ b/src/main/java/chess/controller/State.java @@ -0,0 +1,7 @@ +package chess.controller; + +public enum State { + + RUNNING, + END +} diff --git a/src/main/java/chess/controller/command/Command.java b/src/main/java/chess/controller/command/Command.java new file mode 100644 index 00000000000..5d69660fa42 --- /dev/null +++ b/src/main/java/chess/controller/command/Command.java @@ -0,0 +1,9 @@ +package chess.controller.command; + +import chess.controller.State; +import chess.domain.game.ChessGame; + +public interface Command { + + State execute(ChessGame chessGame); +} diff --git a/src/main/java/chess/controller/command/CommandRouter.java b/src/main/java/chess/controller/command/CommandRouter.java new file mode 100644 index 00000000000..538524184b8 --- /dev/null +++ b/src/main/java/chess/controller/command/CommandRouter.java @@ -0,0 +1,34 @@ +package chess.controller.command; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +public enum CommandRouter { + START("start", Start::new), + END("end", End::new), + MOVE("move", Move::new), + STATUS("status", Status::new); + + private static final int COMMAND_INDEX = 0; + + private final String value; + private final Function, Command> command; + + CommandRouter(String value, + Function, Command> command) { + this.value = value; + this.command = command; + } + + public static Command findCommendByInput(List commandInput) { + if (commandInput == null || commandInput.size() == 0) { + throw new IllegalArgumentException("빈 값 입력을 허용하지 않습니다."); + } + return Arrays.stream(values()) + .filter(commandRouter -> commandRouter.value.equals(commandInput.get(COMMAND_INDEX))) + .map(commandRouter -> commandRouter.command.apply(commandInput)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("옳바르지 않은 명령어 입력입니다.")); + } +} diff --git a/src/main/java/chess/controller/command/End.java b/src/main/java/chess/controller/command/End.java new file mode 100644 index 00000000000..d71193b276e --- /dev/null +++ b/src/main/java/chess/controller/command/End.java @@ -0,0 +1,21 @@ +package chess.controller.command; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import java.util.List; + +public class End implements Command { + + private static final int END_COMMAND_SIZE = 1; + + public End(List commandInput) { + if (commandInput.size() != END_COMMAND_SIZE) { + throw new IllegalArgumentException("게임 종료 명령어 입력 형식이 올바르지 않습니다."); + } + } + + @Override + public State execute(ChessGame chessGame) { + return State.END; + } +} diff --git a/src/main/java/chess/controller/command/Move.java b/src/main/java/chess/controller/command/Move.java new file mode 100644 index 00000000000..1e95381ed8e --- /dev/null +++ b/src/main/java/chess/controller/command/Move.java @@ -0,0 +1,60 @@ +package chess.controller.command; + +import chess.controller.State; +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.ChessGame; +import chess.domain.game.ChessGameResult; +import chess.view.OutputView; +import chess.view.mapper.ColumnMapper; +import chess.view.mapper.RowMapper; +import java.util.List; +import java.util.regex.Pattern; + +public class Move implements Command { + + private static final Pattern POSITION_REGEX = Pattern.compile("" + + "move\\s+([a-h][1-8])\\s+([a-h][1-8])"); + + private final Position from; + private final Position to; + + public Move(List commandInput) { + validateMoveCommandPattern(commandInput); + String fromPosition = commandInput.get(1); + String toPosition = commandInput.get(2); + this.from = createPosition(fromPosition.substring(0, 1), fromPosition.substring(1, 2)); + this.to = createPosition(toPosition.substring(0, 1), toPosition.substring(1, 2)); + } + + private void validateMoveCommandPattern(List commandInput) { + String moveCommand = String.join(" ", commandInput); + if (!POSITION_REGEX.matcher(moveCommand).matches()) { + throw new IllegalArgumentException("게임 이동 명령어 입력 형식이 올바르지 않습니다."); + } + } + + @Override + public State execute(ChessGame chessGame) { + if (chessGame.isCheckmate(to)) { + ChessGameResult chessGameResult = chessGame.generateGameResult(to); + moveAndPrintBoard(chessGame); + OutputView.printChessGameResult(chessGameResult); + return State.END; + } + moveAndPrintBoard(chessGame); + return State.RUNNING; + } + + private void moveAndPrintBoard(ChessGame chessGame) { + chessGame.movePiece(from, to); + OutputView.printBoard(chessGame.getBoard()); + } + + private Position createPosition(String requestColumn, String requestRow) { + Column column = ColumnMapper.findByInputValue(requestColumn); + Row row = RowMapper.findByInputValue(requestRow); + return new Position(row, column); + } +} diff --git a/src/main/java/chess/controller/command/Start.java b/src/main/java/chess/controller/command/Start.java new file mode 100644 index 00000000000..2f4a39042d2 --- /dev/null +++ b/src/main/java/chess/controller/command/Start.java @@ -0,0 +1,23 @@ +package chess.controller.command; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import chess.view.OutputView; +import java.util.List; + +public class Start implements Command { + + private static final int START_COMMAND_SIZE = 1; + + public Start(List commandInput) { + if (commandInput.size() != START_COMMAND_SIZE) { + throw new IllegalArgumentException("게임 시작 명령어 입력 형식이 올바르지 않습니다."); + } + } + + @Override + public State execute(ChessGame chessGame) { + OutputView.printBoard(chessGame.getBoard()); + return State.RUNNING; + } +} diff --git a/src/main/java/chess/controller/command/Status.java b/src/main/java/chess/controller/command/Status.java new file mode 100644 index 00000000000..135507803fe --- /dev/null +++ b/src/main/java/chess/controller/command/Status.java @@ -0,0 +1,27 @@ +package chess.controller.command; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import chess.domain.game.Score; +import chess.domain.piece.Color; +import chess.view.OutputView; +import java.util.List; +import java.util.Map; + +public class Status implements Command { + + private static final int STATUS_COMMAND_SIZE = 1; + + public Status(List commandInput) { + if (commandInput.size() != STATUS_COMMAND_SIZE) { + throw new IllegalArgumentException("게임 점수 명령어 입력 형식이 올바르지 않습니다."); + } + } + + @Override + public State execute(ChessGame chessGame) { + Map teamScore = chessGame.calculateScore(); + OutputView.printTeamScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); + return State.RUNNING; + } +} diff --git a/src/main/java/chess/domain/board/Board.java b/src/main/java/chess/domain/board/Board.java index 2255dea199e..337a675e464 100644 --- a/src/main/java/chess/domain/board/Board.java +++ b/src/main/java/chess/domain/board/Board.java @@ -57,6 +57,14 @@ public void movePiece(Position from, Position to) { board.remove(from); } + public boolean isCheckmate(Position to) { + if (existPiece(to)) { + Piece piece = board.get(to); + return piece.isKing(); + } + return false; + } + public Piece findPieceByPosition(Position position) { if (existPiece(position)) { return board.get(position); @@ -75,8 +83,4 @@ public boolean existPiece(Position position) { public Map getBoard() { return board; } - - void put(Position position, Piece piece) { - board.put(position, piece); - } } diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java index 6cd59f64c28..12d45f360e4 100644 --- a/src/main/java/chess/domain/game/ChessGame.java +++ b/src/main/java/chess/domain/game/ChessGame.java @@ -1,6 +1,7 @@ package chess.domain.game; import chess.domain.board.Board; +import chess.domain.board.BoardFactory; import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.piece.Color; @@ -16,12 +17,21 @@ public class ChessGame { private final Board board; private Color currentTurn; - public ChessGame(Board board) { - this.board = board; + public ChessGame() { + this.board = new Board(new BoardFactory().initialize()); currentTurn = START_TURN; } - public Map calculateTeamScore() { + public ChessGameResult generateGameResult(Position to) { + Map teamScore = board.calculateScore(); + if (board.isCheckmate(to)) { + Piece king = board.findPieceByPosition(to); + return new ChessGameResult(Winner.selectWinnerByCheckmate(king.getColor()), teamScore); + } + return new ChessGameResult(Winner.selectWinnerByScore(teamScore), teamScore); + } + + public Map calculateScore() { return board.calculateScore(); } @@ -36,6 +46,10 @@ public void movePiece(Position from, Position to) { throw new IllegalArgumentException("기물을 해당 위치로 이동시킬 수 없습니다."); } + public boolean isCheckmate(Position to) { + return board.isCheckmate(to); + } + private void validateUserTurn(Position from) { Piece piece = board.findPieceByPosition(from); if (piece.isNotSameColor(currentTurn)) { diff --git a/src/main/java/chess/domain/game/ChessGameResult.java b/src/main/java/chess/domain/game/ChessGameResult.java new file mode 100644 index 00000000000..157661523e2 --- /dev/null +++ b/src/main/java/chess/domain/game/ChessGameResult.java @@ -0,0 +1,23 @@ +package chess.domain.game; + +import chess.domain.piece.Color; +import java.util.Map; + +public class ChessGameResult { + + private final Winner winner; + private final Map teamScore; + + public ChessGameResult(Winner winner, Map teamScore) { + this.winner = winner; + this.teamScore = teamScore; + } + + public Winner getWinner() { + return winner; + } + + public Map getTeamScore() { + return teamScore; + } +} diff --git a/src/main/java/chess/domain/game/Score.java b/src/main/java/chess/domain/game/Score.java new file mode 100644 index 00000000000..9e64f242034 --- /dev/null +++ b/src/main/java/chess/domain/game/Score.java @@ -0,0 +1,38 @@ +package chess.domain.game; + +import java.util.Objects; + +public final class Score { + private final Double score; + + public Score(Double score) { + this.score = score; + } + + public boolean isGreaterThan(Score other) { + return score > other.score; + } + + public boolean isLowerThan(Score other) { + return score < other.score; + } + + public Double score() { + return score; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || obj.getClass() != this.getClass()) + return false; + var that = (Score) obj; + return Objects.equals(this.score, that.score); + } + + @Override + public int hashCode() { + return Objects.hash(score); + } +} diff --git a/src/main/java/chess/domain/game/Winner.java b/src/main/java/chess/domain/game/Winner.java new file mode 100644 index 00000000000..b1cf31279c6 --- /dev/null +++ b/src/main/java/chess/domain/game/Winner.java @@ -0,0 +1,33 @@ +package chess.domain.game; + +import chess.domain.piece.Color; +import java.util.Arrays; +import java.util.Map; +import java.util.function.BiPredicate; + +public enum Winner { + + WHITE_WIN(Score::isGreaterThan), + BLACK_WIN(Score::isLowerThan), + DRAW(Score::equals); + + private final BiPredicate selectWinner; + + Winner(BiPredicate selectWinner) { + this.selectWinner = selectWinner; + } + + public static Winner selectWinnerByScore(Map teamScore) { + return Arrays.stream(values()) + .filter(winner -> winner.selectWinner.test(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK))) + .findFirst() + .orElseThrow(IllegalStateException::new); + } + + public static Winner selectWinnerByCheckmate(Color kingColor) { + if (kingColor == Color.WHITE) { + return BLACK_WIN; + } + return WHITE_WIN; + } +} diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index 8fe46876cca..56be9fecea6 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -39,10 +39,18 @@ public boolean isPawnByColor(Color color) { return pieceType.isWhitePawn(); } + public boolean isKing() { + return this.pieceType == PieceType.KING; + } + public double getScore() { return pieceType.getScore(); } + public Color getColor() { + return color; + } + public boolean isPawnAttackPossible(Direction direction) { if (pieceType == PieceType.BLACK_PAWN) { return direction == Direction.SW || direction == Direction.SE; diff --git a/src/main/java/chess/view/Command.java b/src/main/java/chess/view/Command.java deleted file mode 100644 index c3f4c39cf58..00000000000 --- a/src/main/java/chess/view/Command.java +++ /dev/null @@ -1,26 +0,0 @@ -package chess.view; - -import java.util.Arrays; - -public enum Command { - START("start"), - END("end"), - MOVE("move"), - STATUS("status"); - - private final String value; - - Command(String value) { - this.value = value; - } - - public static Command inputToCommend(String input) { - if (input == null || input.isBlank()) { - throw new IllegalArgumentException("빈 값 입력을 허용하지 않습니다."); - } - return Arrays.stream(values()) - .filter(command -> command.value.equals(input)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException("옳바르지 않은 명령어 입력입니다.")); - } -} diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index d539839939c..0f6ce9b3219 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -1,27 +1,37 @@ package chess.view; import chess.domain.board.Board; +import chess.domain.board.position.Row; +import chess.domain.game.ChessGameResult; +import chess.domain.game.Score; +import chess.domain.game.Winner; +import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.view.mapper.PieceMapper; +import chess.view.mapper.RowMapper; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class OutputView { private static final String EMPTY_BOARD = ". . . . . . . ."; - public void printStartMessage() { + public static void printStartMessage() { System.out.println("체스 게임을 시작합니다."); System.out.println("게임 시작 : start"); System.out.println("게임 종료 : end"); System.out.println("게임 이동 : move source위치 target위치 - 예. move b2 b3"); + System.out.println("게임 점수 : status"); } - public void printBoard(Board board) { + public static void printBoard(Board board) { List result = new ArrayList<>(); for (int i = 0; i < 8; i++) { - result.add(new StringBuilder(EMPTY_BOARD)); + result.add(new StringBuilder(EMPTY_BOARD + " | " + RowMapper.findByRow(Row.findByIndex(i)))); } + result.add(new StringBuilder("ㅡㅡㅡㅡㅡㅡㅡㅡㅡ")); + result.add(new StringBuilder("a b c d e f g h")); board.getBoard().keySet() .forEach(position -> { @@ -35,13 +45,31 @@ public void printBoard(Board board) { System.out.println(); } - public void printTeamScore(double whiteTeamScore, double blackTeamScore) { - System.out.println("---현재 점수---"); - System.out.println("흰색 팀: " + whiteTeamScore); - System.out.println("검정 팀: " + blackTeamScore); + public static void printChessGameResult(ChessGameResult chessGameResult) { + StringBuilder stringBuilder = new StringBuilder("왕이 잡혀서 게임이 종료되었습니다. \n체스 게임 결과 : "); + Winner winner = chessGameResult.getWinner(); + Map teamScore = chessGameResult.getTeamScore(); + if (winner == Winner.WHITE_WIN) { + stringBuilder.append("흰색 팀 승리!"); + } + if (winner == Winner.BLACK_WIN) { + stringBuilder.append("검정 팀 승리!"); + } + if (winner == Winner.DRAW) { + stringBuilder.append("무승부!"); + } + + System.out.println(stringBuilder); + printTeamScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); + } + + public static void printTeamScore(Score whiteTeamScore, Score blackTeamScore) { + System.out.println("--- 점수 ---"); + System.out.println("흰색 팀: " + whiteTeamScore.score()); + System.out.println("검정 팀: " + blackTeamScore.score()); } - public void printError(Exception exception) { + public static void printError(Exception exception) { System.out.println(exception.getMessage()); } } diff --git a/src/test/java/chess/controller/command/CommandRouterTest.java b/src/test/java/chess/controller/command/CommandRouterTest.java new file mode 100644 index 00000000000..ab80e16f58e --- /dev/null +++ b/src/test/java/chess/controller/command/CommandRouterTest.java @@ -0,0 +1,59 @@ +package chess.controller.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CommandRouterTest { + + @DisplayName("게임 시작 커맨드를 반환한다.") + @Test + void findStartCommendByInputTest() { + Command start = CommandRouter.findCommendByInput(List.of("start")); + + assertThat(start).isInstanceOf(Start.class); + } + + @DisplayName("게임 이동 커맨드를 반환한다.") + @Test + void findMoveCommendByInputTest() { + Command start = CommandRouter.findCommendByInput(List.of("move", "b2", "b4")); + + assertThat(start).isInstanceOf(Move.class); + } + + @DisplayName("게임 종료 커맨드를 반환한다.") + @Test + void findEndCommendByInputTest() { + Command start = CommandRouter.findCommendByInput(List.of("end")); + + assertThat(start).isInstanceOf(End.class); + } + + @DisplayName("게임 점수 커맨드를 반환한다.") + @Test + void findStatusCommendByInputTest() { + Command start = CommandRouter.findCommendByInput(List.of("status")); + + assertThat(start).isInstanceOf(Status.class); + } + + @DisplayName("커맨드 입력 리스트 크기가 0이면 에러를 발생시킨다.") + @Test + void commendInputFormatSizeTest() { + assertThatThrownBy(() -> CommandRouter.findCommendByInput(List.of())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("빈 값 입력을 허용하지 않습니다."); + } + + @DisplayName("입력과 일치하는 커맨드를 찾지 못하면 에러를 발생시킨다.") + @Test + void findCommendByInputFailTest() { + assertThatThrownBy(() -> CommandRouter.findCommendByInput(List.of("jazz"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("옳바르지 않은 명령어 입력입니다."); + } +} diff --git a/src/test/java/chess/controller/command/EndTest.java b/src/test/java/chess/controller/command/EndTest.java new file mode 100644 index 00000000000..9d4ac6c80b1 --- /dev/null +++ b/src/test/java/chess/controller/command/EndTest.java @@ -0,0 +1,40 @@ +package chess.controller.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class EndTest { + + @DisplayName("명령어 입력이 end로만 이루어져 있으면 정상적으로 생성된다.") + @Test + void validateCommandInputSizeSuccessTest() { + assertThatNoException() + .isThrownBy(() -> new End(List.of("end"))); + } + + @DisplayName("명령어 입력이 end로만 이루어져 있지 않으면 에러를 발생시킨다..") + @Test + void validateCommandInputSizeFailTest() { + assertThatThrownBy(() -> new End(List.of("end", "asd", " "))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("게임 종료 명령어 입력 형식이 올바르지 않습니다."); + } + + @DisplayName("기능을 수행한 후 END 상태를 반환한다.") + @Test + void executeTest() { + End end = new End(List.of("end")); + ChessGame chessGame = new ChessGame(); + + State gameState = end.execute(chessGame); + + assertThat(gameState).isEqualTo(State.END); + } +} diff --git a/src/test/java/chess/controller/command/MoveTest.java b/src/test/java/chess/controller/command/MoveTest.java new file mode 100644 index 00000000000..a37a532acf6 --- /dev/null +++ b/src/test/java/chess/controller/command/MoveTest.java @@ -0,0 +1,40 @@ +package chess.controller.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class MoveTest { + + @DisplayName("명령어 입력 형식이 올바르면 정상적으로 생성된다.") + @Test + void validateCommandInputSizeSuccessTest() { + assertThatNoException() + .isThrownBy(() -> new Move(List.of("move", "c2", "c3"))); + } + + @DisplayName("명령어 입력이 올바르지 않으면 에러를 발생시킨다..") + @Test + void validateCommandInputSizeFailTest() { + assertThatThrownBy(() -> new Move(List.of("move", "ff", "f0", " "))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("게임 이동 명령어 입력 형식이 올바르지 않습니다."); + } + + @DisplayName("기능을 수행한 후 RUNNING 상태를 반환한다.") + @Test + void executeTest() { + Move move = new Move(List.of("move", "b2", "b4")); + ChessGame chessGame = new ChessGame(); + + State gameState = move.execute(chessGame); + + assertThat(gameState).isEqualTo(State.RUNNING); + } +} diff --git a/src/test/java/chess/controller/command/StartTest.java b/src/test/java/chess/controller/command/StartTest.java new file mode 100644 index 00000000000..60a952b565e --- /dev/null +++ b/src/test/java/chess/controller/command/StartTest.java @@ -0,0 +1,41 @@ +package chess.controller.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class StartTest { + + @DisplayName("명령어 입력이 start로만 이루어져 있으면 정상적으로 생성된다.") + @Test + void validateCommandInputSize() { + assertThatNoException() + .isThrownBy(() -> new Start(List.of("start"))); + } + + @DisplayName("명령어 입력이 start로만 이루어져 있지 않으면 에러를 발생시킨다..") + @Test + void validateCommandInputSizeFailTest() { + assertThatThrownBy(() -> new Start(List.of("start", "2", " "))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("게임 시작 명령어 입력 형식이 올바르지 않습니다."); + } + + @DisplayName("기능을 수행한 후 RUNNING 상태를 반환한다.") + @Test + void executeTest() { + Start start = new Start(List.of("start")); + ChessGame chessGame = new ChessGame(); + + State gameState = start.execute(chessGame); + + assertThat(gameState).isEqualTo(State.RUNNING); + } + +} diff --git a/src/test/java/chess/controller/command/StatusTest.java b/src/test/java/chess/controller/command/StatusTest.java new file mode 100644 index 00000000000..1e9d7840425 --- /dev/null +++ b/src/test/java/chess/controller/command/StatusTest.java @@ -0,0 +1,41 @@ +package chess.controller.command; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.controller.State; +import chess.domain.game.ChessGame; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class StatusTest { + + @DisplayName("명령어 입력이 status로만 이루어져 있으면 정상적으로 생성된다.") + @Test + void validateCommandInputSizeSuccessTest() { + assertThatNoException() + .isThrownBy(() -> new Status(List.of("status"))); + } + + @DisplayName("명령어 입력이 status로만 이루어져 있지 않으면 에러를 발생시킨다..") + @Test + void validateCommandInputSizeFailTest() { + assertThatThrownBy(() -> new Status(List.of("status", " "))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("게임 점수 명령어 입력 형식이 올바르지 않습니다."); + } + + @DisplayName("기능을 수행한 후 RUNNING 상태를 반환한다.") + @Test + void executeTest() { + Status status = new Status(List.of("status")); + ChessGame chessGame = new ChessGame(); + + State gameState = status.execute(chessGame); + + assertThat(gameState).isEqualTo(State.RUNNING); + } + +} diff --git a/src/test/java/chess/domain/game/WinnerTest.java b/src/test/java/chess/domain/game/WinnerTest.java new file mode 100644 index 00000000000..fd439dc01ca --- /dev/null +++ b/src/test/java/chess/domain/game/WinnerTest.java @@ -0,0 +1,68 @@ +package chess.domain.game; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.piece.Color; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class WinnerTest { + + @Nested + @DisplayName("점수로 승리를 결정한다.") + class SelectWinnerByScoreTest { + + @DisplayName("흰색 팀의 점수가 검정 팀보다 높으면 흰색 팀이 승리한다.") + @Test + void whiteTeamScoreIsGreaterThanBlackTeam() { + Map map = Map.of(Color.WHITE, new Score(33.0), Color.BLACK, new Score(27.0)); + + Winner winner = Winner.selectWinnerByScore(map); + + assertThat(winner).isEqualTo(Winner.WHITE_WIN); + } + + @DisplayName("검정 팀의 점수가 흰색 팀보다 높으면 검정 팀이 승리한다.") + @Test + void blackTeamScoreIsGreaterThanWhiteTeam() { + Map map = Map.of(Color.WHITE, new Score(26.9), Color.BLACK, new Score(27.0)); + + Winner winner = Winner.selectWinnerByScore(map); + + assertThat(winner).isEqualTo(Winner.BLACK_WIN); + } + + @DisplayName("검정 팀의 점수가 흰색 팀과 같으면 무승부") + @Test + void blackTeamScoreEqualWhiteTeam() { + Map map = Map.of(Color.WHITE, new Score(27.0), Color.BLACK, new Score(27.0)); + + Winner winner = Winner.selectWinnerByScore(map); + + assertThat(winner).isEqualTo(Winner.DRAW); + } + } + + @Nested + @DisplayName("체크메이트로 승리를 결정한다") + class SelectWinnerByCheckmateTest { + + @DisplayName("검정 색의 King이 체크메이트를 당하면 흰색 팀이 승리한다.") + @Test + void blackKingCheckmateTest() { + Winner winner = Winner.selectWinnerByCheckmate(Color.BLACK); + + assertThat(winner).isEqualTo(Winner.WHITE_WIN); + } + + @DisplayName("흰색 색의 King이 체크메이트를 당하면 검정 팀이 승리한다.") + @Test + void whiteKingCheckmateTest() { + Winner winner = Winner.selectWinnerByCheckmate(Color.WHITE); + + assertThat(winner).isEqualTo(Winner.BLACK_WIN); + } + } +} From 2cb887dea1593ef66bd39cfe658303d8e5212674 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Fri, 29 Mar 2024 20:56:30 +0900 Subject: [PATCH 06/18] =?UTF-8?q?refactor(ChessGameController):=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20Command=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chess/controller/ChessGameController.java | 79 ++++--------------- .../java/chess/domain/board/position/Row.java | 9 ++- src/main/java/chess/view/InputView.java | 30 ++----- src/main/java/chess/view/MoveRequestDto.java | 32 -------- .../java/chess/view/mapper/RowMapper.java | 10 ++- .../java/chess/view/mapper/RowMapperTest.java | 14 ++++ 6 files changed, 50 insertions(+), 124 deletions(-) delete mode 100644 src/main/java/chess/view/MoveRequestDto.java diff --git a/src/main/java/chess/controller/ChessGameController.java b/src/main/java/chess/controller/ChessGameController.java index f3d5f6982e8..c449906eb68 100644 --- a/src/main/java/chess/controller/ChessGameController.java +++ b/src/main/java/chess/controller/ChessGameController.java @@ -1,84 +1,33 @@ package chess.controller; -import chess.domain.board.Board; -import chess.domain.board.position.Column; -import chess.domain.board.position.Position; -import chess.domain.board.position.Row; +import chess.controller.command.Command; +import chess.controller.command.CommandRouter; import chess.domain.game.ChessGame; -import chess.domain.piece.Color; -import chess.view.Command; import chess.view.InputView; -import chess.view.MoveRequestDto; import chess.view.OutputView; -import chess.view.mapper.ColumnMapper; -import chess.view.mapper.RowMapper; -import java.util.Map; public class ChessGameController { - private final InputView inputView = new InputView(); - private final OutputView outputView = new OutputView(); public void run() { - ChessGame chessGame = new ChessGame(new Board()); - outputView.printStartMessage(); + ChessGame chessGame = new ChessGame(); + OutputView.printStartMessage(); process(chessGame); } private void process(ChessGame chessGame) { - boolean isRunning = true; - while (isRunning) { - isRunning = processGame(chessGame); - } + State state = State.RUNNING; + do { + state = executeCommand(chessGame, state); + } while (state != State.END); } - private boolean processGame(ChessGame chessGame) { + private State executeCommand(ChessGame chessGame, State state) { try { - Command command = inputView.readCommend(); - processGameStart(chessGame, command); - processMove(chessGame, command); - processStatus(chessGame, command); - return command != Command.END; - } catch (IllegalArgumentException error) { - outputView.printError(error); - process(chessGame); - return false; - } - } - - private void processStatus(ChessGame chessGame, Command command) { - if (command == Command.STATUS) { - Map teamScore = chessGame.calculateTeamScore(); - outputView.printTeamScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); - } - } - - private void processMove(ChessGame chessGame, Command command) { - if (command == Command.MOVE) { - handleMove(chessGame); - } - } - - private void processGameStart(ChessGame chessGame, Command command) { - if (command == Command.START) { - handleStart(chessGame); + Command command = CommandRouter.findCommendByInput(InputView.readCommend()); + return command.execute(chessGame); + } catch (RuntimeException error) { + OutputView.printError(error); + return state; } } - - private void handleStart(ChessGame chessGame) { - outputView.printBoard(chessGame.getBoard()); - } - - private void handleMove(ChessGame chessGame) { - MoveRequestDto moveRequestDto = inputView.readPositions(); - Position from = createPosition(moveRequestDto.getFromColumn(), moveRequestDto.getFromRow()); - Position to = createPosition(moveRequestDto.getToColumn(), moveRequestDto.getToRow()); - chessGame.movePiece(from, to); - outputView.printBoard(chessGame.getBoard()); - } - - private Position createPosition(String requestColumn, String requestRow) { - Column column = ColumnMapper.findByInputValue(requestColumn); - Row row = RowMapper.findByInputValue(requestRow); - return new Position(row, column); - } } diff --git a/src/main/java/chess/domain/board/position/Row.java b/src/main/java/chess/domain/board/position/Row.java index f82305f6327..6ef0dc404e7 100644 --- a/src/main/java/chess/domain/board/position/Row.java +++ b/src/main/java/chess/domain/board/position/Row.java @@ -26,7 +26,14 @@ public Row calculateNextRow(int distance) { return Arrays.stream(values()) .filter(row -> row.index == this.index + distance) .findAny() - .orElseThrow(() -> new IllegalArgumentException("일치하는 Column 이 없습니다.")); + .orElseThrow(() -> new IllegalArgumentException("다음 위치로 이동할 수 있는 열이 없습니다.")); + } + + public static Row findByIndex(int index) { + return Arrays.stream(values()) + .filter(row -> row.index == index) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("열과 일치하는 인덱스가 없습니다.")); } public boolean isNextInRange(int distance) { diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java index 37125458163..6173e630268 100644 --- a/src/main/java/chess/view/InputView.java +++ b/src/main/java/chess/view/InputView.java @@ -1,34 +1,14 @@ package chess.view; +import java.util.Arrays; +import java.util.List; import java.util.Scanner; -import java.util.regex.Pattern; public class InputView { - private static final Pattern COMMAND_REGEX = Pattern.compile("(move)|(start)|(end)|(status)"); - private static final Pattern POSITION_REGEX = Pattern.compile("([a-h][1-8]\\s+[a-h][1-8])"); + private static final Scanner scanner = new Scanner(System.in); - private final Scanner scanner = new Scanner(System.in); - - public Command readCommend() { - String input = scanner.next(); - if (!COMMAND_REGEX.matcher(input).matches()) { - throw new IllegalArgumentException("입력한 체스 게임 명령어가 올바르지 않습니다."); - } - return Command.inputToCommend(input); - } - - public MoveRequestDto readPositions() { - String input = scanner.nextLine().strip(); - if (!POSITION_REGEX.matcher(input).matches()) { - throw new IllegalArgumentException("입력한 이동 명령 형식이 올바르지 않습니다."); - } - - return new MoveRequestDto( - input.substring(0, 1), - input.substring(1, 2), - input.substring(3, 4), - input.substring(4, 5) - ); + public static List readCommend() { + return Arrays.stream(scanner.nextLine().split(" ")).toList(); } } diff --git a/src/main/java/chess/view/MoveRequestDto.java b/src/main/java/chess/view/MoveRequestDto.java deleted file mode 100644 index 74e67b36383..00000000000 --- a/src/main/java/chess/view/MoveRequestDto.java +++ /dev/null @@ -1,32 +0,0 @@ -package chess.view; - -public class MoveRequestDto { - - private final String fromColumn; - private final String fromRow; - private final String toColumn; - private final String toRow; - - public MoveRequestDto(String fromColumn, String fromRow, String toColumn, String toRow) { - this.fromColumn = fromColumn; - this.fromRow = fromRow; - this.toColumn = toColumn; - this.toRow = toRow; - } - - public String getFromColumn() { - return fromColumn; - } - - public String getFromRow() { - return fromRow; - } - - public String getToColumn() { - return toColumn; - } - - public String getToRow() { - return toRow; - } -} diff --git a/src/main/java/chess/view/mapper/RowMapper.java b/src/main/java/chess/view/mapper/RowMapper.java index 6242990d472..92c8999cae3 100644 --- a/src/main/java/chess/view/mapper/RowMapper.java +++ b/src/main/java/chess/view/mapper/RowMapper.java @@ -25,7 +25,15 @@ public static Row findByInputValue(String value) { return Arrays.stream(values()) .filter(row -> row.value.equals(value)) .findAny() - .orElseThrow(() -> new IllegalArgumentException("일치하는 Column 이 없습니다.")) + .orElseThrow(() -> new IllegalArgumentException("입력과 일치하는 열이 존재하지 않습니다.")) .row; } + + public static String findByRow(Row row) { + return Arrays.stream(values()) + .filter(rowMapper -> rowMapper.row == row) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("열과 일치하는 문자열이 존재하지 않습니다.")) + .value; + } } diff --git a/src/test/java/chess/view/mapper/RowMapperTest.java b/src/test/java/chess/view/mapper/RowMapperTest.java index db6f60635ff..dca694cd741 100644 --- a/src/test/java/chess/view/mapper/RowMapperTest.java +++ b/src/test/java/chess/view/mapper/RowMapperTest.java @@ -35,4 +35,18 @@ void findByInputValueFailTest(String value) { .isInstanceOf(IllegalArgumentException.class); } + @Test + @DisplayName("Row로 문자열을 찾는다.") + void findByRowSuccessTest() { + assertAll( + () -> assertEquals("1", RowMapper.findByRow(Row.ONE)), + () -> assertEquals("2", RowMapper.findByRow(Row.TWO)), + () -> assertEquals("3", RowMapper.findByRow(Row.THREE)), + () -> assertEquals("4", RowMapper.findByRow(Row.FOUR)), + () -> assertEquals("5", RowMapper.findByRow(Row.FIVE)), + () -> assertEquals("6", RowMapper.findByRow(Row.SIX)), + () -> assertEquals("7", RowMapper.findByRow(Row.SEVEN)), + () -> assertEquals("8", RowMapper.findByRow(Row.EIGHT)) + ); + } } From 5c47f7846fd7e657f37774dec0af5108434d46e7 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sat, 30 Mar 2024 19:37:41 +0900 Subject: [PATCH 07/18] =?UTF-8?q?refactor(Row):=20enum=EC=9D=98=20?= =?UTF-8?q?=EC=9D=B8=EB=8D=B1=EC=8A=A4=EB=A5=BC=20=EC=97=AD=EC=88=9C?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=88=9C=EC=84=9C=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/board/position/Direction.java | 30 +++++++++---------- .../chess/domain/board/position/Position.java | 14 ++++----- .../java/chess/domain/board/position/Row.java | 20 +++++-------- src/main/java/chess/view/OutputView.java | 15 +++++----- .../java/chess/view/mapper/RowMapper.java | 28 +++++++++++------ src/test/java/chess/domain/board/RowTest.java | 11 +++---- .../chess/view/mapper/ColumnMapperTest.java | 2 +- 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/main/java/chess/domain/board/position/Direction.java b/src/main/java/chess/domain/board/position/Direction.java index f31b62a3ddc..ca84ab9d3f0 100644 --- a/src/main/java/chess/domain/board/position/Direction.java +++ b/src/main/java/chess/domain/board/position/Direction.java @@ -1,24 +1,24 @@ package chess.domain.board.position; public enum Direction { - N(-1, 0), + N(1, 0), E(0, 1), - S(1, 0), + S(-1, 0), W(0, -1), - NE(-1, 1), - SE(1, 1), - SW(1, -1), - NW(-1, -1), - - NNE(-2, 1), - ENE(-1, 2), - ESE(1, 2), - SSE(2, 1), - SSW(2, -1), - WSW(1, -2), - WNW(-1, -2), - NNW(-2, -1); + NE(1, 1), + SE(-1, 1), + SW(-1, -1), + NW(1, -1), + + NNE(2, 1), + ENE(1, 2), + ESE(-1, 2), + SSE(-2, 1), + SSW(-2, -1), + WSW(-1, -2), + WNW(1, -2), + NNW(2, -1); private final int rowDirection; private final int columnDirection; diff --git a/src/main/java/chess/domain/board/position/Position.java b/src/main/java/chess/domain/board/position/Position.java index 3174e85b979..74ac9ca175f 100644 --- a/src/main/java/chess/domain/board/position/Position.java +++ b/src/main/java/chess/domain/board/position/Position.java @@ -16,10 +16,7 @@ public Position(Row row, Column column) { public Position calculateNextPosition(Direction direction, int weight) { int rowDistance = direction.calculateRowDistance(weight); int columnDistance = direction.calculateColumnDistance(weight); - - Row nextRow = row.calculateNextRow(rowDistance); - Column nextColumn = column.calculateNextColumn(columnDistance); - return new Position(nextRow, nextColumn); + return new Position(row.calculateNextRow(rowDistance), column.calculateNextColumn(columnDistance)); } public int calculateMaxDistance(Direction direction, int maxMoveDistance) { @@ -32,7 +29,6 @@ public int calculateMaxDistance(Direction direction, int maxMoveDistance) { private boolean isInRange(Direction direction, int weight) { int rowDistance = direction.calculateRowDistance(weight); int columnDistance = direction.calculateColumnDistance(weight); - return row.isNextInRange(rowDistance) && column.isNextInRange(columnDistance); } @@ -40,14 +36,14 @@ public boolean isSameRow(Row row) { return this.row == row; } - public int getRowIndex() { - return row.getIndex(); - } - public int getColumnIndex() { return column.getIndex(); } + public Row getRow() { + return row; + } + public Column getColumn() { return column; } diff --git a/src/main/java/chess/domain/board/position/Row.java b/src/main/java/chess/domain/board/position/Row.java index 6ef0dc404e7..7101a5a8f3c 100644 --- a/src/main/java/chess/domain/board/position/Row.java +++ b/src/main/java/chess/domain/board/position/Row.java @@ -3,14 +3,14 @@ import java.util.Arrays; public enum Row { - ONE(7), - TWO(6), - THREE(5), + EIGHT(8), + SEVEN(7), + SIX(6), + FIVE(5), FOUR(4), - FIVE(3), - SIX(2), - SEVEN(1), - EIGHT(0); + THREE(3), + TWO(2), + ONE(1); private final int index; @@ -18,10 +18,6 @@ public enum Row { this.index = index; } - public int getIndex() { - return index; - } - public Row calculateNextRow(int distance) { return Arrays.stream(values()) .filter(row -> row.index == this.index + distance) @@ -38,6 +34,6 @@ public static Row findByIndex(int index) { public boolean isNextInRange(int distance) { int nextIndex = index + distance; - return EIGHT.index <= nextIndex && nextIndex <= ONE.index; + return EIGHT.index >= nextIndex && nextIndex >= ONE.index; } } diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index 0f6ce9b3219..bf83addc618 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -27,7 +27,7 @@ public static void printStartMessage() { public static void printBoard(Board board) { List result = new ArrayList<>(); - for (int i = 0; i < 8; i++) { + for (int i = 1; i <= 8; i++) { result.add(new StringBuilder(EMPTY_BOARD + " | " + RowMapper.findByRow(Row.findByIndex(i)))); } result.add(new StringBuilder("ㅡㅡㅡㅡㅡㅡㅡㅡㅡ")); @@ -36,7 +36,8 @@ public static void printBoard(Board board) { board.getBoard().keySet() .forEach(position -> { Piece piece = board.getBoard().get(position); - int rowIndex = position.getRowIndex(); +// int rowIndex = position.getRowIndex(); + int rowIndex = RowMapper.findByIndex(position.getRow()); int columnIndex = position.getColumnIndex(); result.get(rowIndex).replace(columnIndex * 2, columnIndex * 2 + 1, PieceMapper.findByPieceType(piece)); }); @@ -50,10 +51,10 @@ public static void printChessGameResult(ChessGameResult chessGameResult) { Winner winner = chessGameResult.getWinner(); Map teamScore = chessGameResult.getTeamScore(); if (winner == Winner.WHITE_WIN) { - stringBuilder.append("흰색 팀 승리!"); + stringBuilder.append("흰색 승리!"); } if (winner == Winner.BLACK_WIN) { - stringBuilder.append("검정 팀 승리!"); + stringBuilder.append("검정 승리!"); } if (winner == Winner.DRAW) { stringBuilder.append("무승부!"); @@ -64,9 +65,9 @@ public static void printChessGameResult(ChessGameResult chessGameResult) { } public static void printTeamScore(Score whiteTeamScore, Score blackTeamScore) { - System.out.println("--- 점수 ---"); - System.out.println("흰색 팀: " + whiteTeamScore.score()); - System.out.println("검정 팀: " + blackTeamScore.score()); + System.out.println("--- 기물 점수 ---"); + System.out.println("흰색: " + whiteTeamScore.score()); + System.out.println("검정: " + blackTeamScore.score()); } public static void printError(Exception exception) { diff --git a/src/main/java/chess/view/mapper/RowMapper.java b/src/main/java/chess/view/mapper/RowMapper.java index 92c8999cae3..22c1f867328 100644 --- a/src/main/java/chess/view/mapper/RowMapper.java +++ b/src/main/java/chess/view/mapper/RowMapper.java @@ -4,21 +4,23 @@ import java.util.Arrays; public enum RowMapper { - RANK1(Row.ONE, "1"), - RANK2(Row.TWO, "2"), - RANK3(Row.THREE, "3"), - RANK4(Row.FOUR, "4"), - RANK5(Row.FIVE, "5"), - RANK6(Row.SIX, "6"), - RANK7(Row.SEVEN, "7"), - RANK8(Row.EIGHT, "8"); + RANK1(Row.ONE, "1", 7), + RANK2(Row.TWO, "2", 6), + RANK3(Row.THREE, "3", 5), + RANK4(Row.FOUR, "4", 4), + RANK5(Row.FIVE, "5", 3), + RANK6(Row.SIX, "6", 2), + RANK7(Row.SEVEN, "7", 1), + RANK8(Row.EIGHT, "8", 0); private final Row row; private final String value; + private final int arrayIndex; - RowMapper(Row row, String value) { + RowMapper(Row row, String value, int arrayIndex) { this.row = row; this.value = value; + this.arrayIndex = arrayIndex; } public static Row findByInputValue(String value) { @@ -36,4 +38,12 @@ public static String findByRow(Row row) { .orElseThrow(() -> new IllegalArgumentException("열과 일치하는 문자열이 존재하지 않습니다.")) .value; } + + public static int findByIndex(Row row) { + return Arrays.stream(values()) + .filter(rowMapper -> rowMapper.row == row) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("열과 일치하는 인덱스가 존재하지 않습니다.")) + .arrayIndex; + } } diff --git a/src/test/java/chess/domain/board/RowTest.java b/src/test/java/chess/domain/board/RowTest.java index f074a1013b3..d2d1a5abefb 100644 --- a/src/test/java/chess/domain/board/RowTest.java +++ b/src/test/java/chess/domain/board/RowTest.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import chess.domain.board.position.Row; import org.junit.jupiter.api.DisplayName; @@ -18,8 +17,8 @@ void calculateNextRowSuccessTest() { Row row = Row.FOUR; assertAll( - () -> assertEquals(Row.FIVE, row.calculateNextRow(-1)), - () -> assertEquals(Row.THREE, row.calculateNextRow(1)), + () -> assertEquals(Row.FIVE, row.calculateNextRow(1)), + () -> assertEquals(Row.THREE, row.calculateNextRow(-1)), () -> assertEquals(Row.FOUR, row.calculateNextRow(0)) ); } @@ -37,10 +36,8 @@ void calculateNextRowFailTest() { @DisplayName("거리 만큼 이동한 값이 보드판을 벗어난 경우 false를 반환한다.") void isNextInRange() { assertAll( - () -> assertTrue(Row.FOUR.isNextInRange(-1)), - () -> assertTrue(Row.FOUR.isNextInRange(1)), - () -> assertFalse(Row.EIGHT.isNextInRange(-1)), - () -> assertFalse(Row.ONE.isNextInRange(1)) + () -> assertFalse(Row.EIGHT.isNextInRange(1)), + () -> assertFalse(Row.ONE.isNextInRange(-1)) ); } } diff --git a/src/test/java/chess/view/mapper/ColumnMapperTest.java b/src/test/java/chess/view/mapper/ColumnMapperTest.java index 115d5246499..b65381001ed 100644 --- a/src/test/java/chess/view/mapper/ColumnMapperTest.java +++ b/src/test/java/chess/view/mapper/ColumnMapperTest.java @@ -13,7 +13,7 @@ class ColumnMapperTest { @Test - @DisplayName("이름으로 Column를 찾는다.") + @DisplayName("문자열로 Column를 찾는다.") void findByInputValueSuccessTest() { assertAll( () -> assertEquals(Column.A, ColumnMapper.findByInputValue("a")), From 972d9d85be5049a152fa9aa1ebbb4930f34931b1 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 15:02:52 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat(BoardRepository):=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20Board=EB=A5=BC=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=91=EA=B7=BC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20BoardRepository=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + src/main/java/chess/domain/board/Board.java | 86 ----------- .../chess/repository/BoardRepository.java | 27 ++++ .../chess/repository/BoardRepositoryImpl.java | 139 ++++++++++++++++++ .../java/chess/repository/DBConnection.java | 23 +++ .../java/chess/repository/QueryProcessor.java | 10 ++ .../domain/mock/BlackPieceRepository.java | 50 +++++++ .../domain/mock/NotExistsPieceRepository.java | 48 ++++++ .../domain/mock/WhitePieceRepository.java | 48 ++++++ .../domain/positionFilter/BishopTest.java | 87 +++++++---- .../domain/positionFilter/BlackPawnTest.java | 118 --------------- .../chess/domain/positionFilter/KingTest.java | 93 +++++++----- .../domain/positionFilter/KnightTest.java | 94 +++++++----- .../chess/domain/positionFilter/PawnTest.java | 71 +++++++++ .../domain/positionFilter/QueenTest.java | 121 ++++++++++----- .../chess/domain/positionFilter/RookTest.java | 86 +++++++---- .../domain/positionFilter/WhitePawnTest.java | 118 --------------- 17 files changed, 732 insertions(+), 489 deletions(-) delete mode 100644 src/main/java/chess/domain/board/Board.java create mode 100644 src/main/java/chess/repository/BoardRepository.java create mode 100644 src/main/java/chess/repository/BoardRepositoryImpl.java create mode 100644 src/main/java/chess/repository/DBConnection.java create mode 100644 src/main/java/chess/repository/QueryProcessor.java create mode 100644 src/test/java/chess/domain/mock/BlackPieceRepository.java create mode 100644 src/test/java/chess/domain/mock/NotExistsPieceRepository.java create mode 100644 src/test/java/chess/domain/mock/WhitePieceRepository.java delete mode 100644 src/test/java/chess/domain/positionFilter/BlackPawnTest.java create mode 100644 src/test/java/chess/domain/positionFilter/PawnTest.java delete mode 100644 src/test/java/chess/domain/positionFilter/WhitePawnTest.java diff --git a/build.gradle b/build.gradle index 3697236c6fb..20ad08a5a5e 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,8 @@ 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/domain/board/Board.java b/src/main/java/chess/domain/board/Board.java deleted file mode 100644 index 337a675e464..00000000000 --- a/src/main/java/chess/domain/board/Board.java +++ /dev/null @@ -1,86 +0,0 @@ -package chess.domain.board; - -import chess.domain.board.position.Column; -import chess.domain.board.position.Position; -import chess.domain.game.Score; -import chess.domain.piece.Color; -import chess.domain.piece.Piece; -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; - -public class Board { - - private final Map board; - - public Board(Map board) { - this.board = board; - } - - public Map calculateScore() { - return Arrays.stream(Color.values()).collect(Collectors.toMap( - color -> color, - this::calculateTotalScore - )); - } - - private Score calculateTotalScore(Color color) { - double sum = sumTotalScore(color); - double pawnMinus = calculatePawnScore(color); - return new Score(sum - pawnMinus); - } - - private double sumTotalScore(Color color) { - return board.values().stream() - .filter(piece -> piece.isSameColor(color)) - .mapToDouble(Piece::getScore) - .sum(); - } - - private Map countPawnByColumn(Color color) { - return board.keySet().stream() - .filter(position -> board.get(position).isPawnByColor(color)) - .collect(Collectors.groupingBy(Position::getColumn, Collectors.counting())); - } - - private double calculatePawnScore(Color color) { - Map pawnCountByColumn = countPawnByColumn(color); - return pawnCountByColumn.values().stream() - .filter(pawnCount -> pawnCount >= 2) - .mapToDouble(pawnCount -> pawnCount * 0.5) - .sum(); - } - - public void movePiece(Position from, Position to) { - Piece fromPiece = board.get(from); - board.put(to, fromPiece); - board.remove(from); - } - - public boolean isCheckmate(Position to) { - if (existPiece(to)) { - Piece piece = board.get(to); - return piece.isKing(); - } - return false; - } - - public Piece findPieceByPosition(Position position) { - if (existPiece(position)) { - return board.get(position); - } - throw new IllegalArgumentException("해당 위치에 기물이 없습니다."); - } - - public boolean isEmptySpace(Position position) { - return !existPiece(position); - } - - public boolean existPiece(Position position) { - return board.containsKey(position); - } - - public Map getBoard() { - return board; - } -} diff --git a/src/main/java/chess/repository/BoardRepository.java b/src/main/java/chess/repository/BoardRepository.java new file mode 100644 index 00000000000..f3dfe250e07 --- /dev/null +++ b/src/main/java/chess/repository/BoardRepository.java @@ -0,0 +1,27 @@ +package chess.repository; + +import chess.domain.board.position.Position; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; + +public interface BoardRepository { + + void savePiece(Piece piece, Position position); + + boolean existsPieceByPosition(Position position); + + void deletePieceByPosition(Position position); + + Piece findPieceByPosition(Position position); + + List findPieceByColor(Color color); + + List getPieceCountByPieceType(PieceType pieceType); + + Map findAllPiece(); + + List findPieceByPieceType(PieceType pieceType); +} diff --git a/src/main/java/chess/repository/BoardRepositoryImpl.java b/src/main/java/chess/repository/BoardRepositoryImpl.java new file mode 100644 index 00000000000..c874850245a --- /dev/null +++ b/src/main/java/chess/repository/BoardRepositoryImpl.java @@ -0,0 +1,139 @@ +package chess.repository; + +import chess.domain.board.position.Position; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BoardRepositoryImpl implements BoardRepository { + + private final DBConnection dbConnection = new DBConnection(); + + @Override + public void savePiece(Piece piece, Position position) { + final String query = "INSERT INTO board(`row`, `column`, piece_type, piece_color) VALUES(?, ?, ?, ?)"; + processQuery(query, preparedStatement -> { + preparedStatement.setInt(1, position.getRowIndex()); + preparedStatement.setString(2, position.getColumn().name()); + preparedStatement.setString(3, piece.getPieceType().name()); + preparedStatement.setString(4, piece.getColor().name()); + preparedStatement.executeUpdate(); + }); + } + + @Override + public boolean existsPieceByPosition(Position position) { + List existsPiece = new ArrayList<>(); + final String query = "SELECT EXISTS (" + + "SELECT 1 FROM board WHERE `row` = ? AND `column` = ?) AS exists_piece"; + processQuery(query, preparedStatement -> { + preparedStatement.setInt(1, position.getRowIndex()); + preparedStatement.setString(2, position.getColumn().name()); + ResultSet rs = preparedStatement.executeQuery(); + if (rs.next()) { + existsPiece.add(rs.getBoolean("exists_piece")); + } + }); + return existsPiece.get(0); + } + + @Override + public void deletePieceByPosition(Position position) { + final String query = "DELETE FROM board WHERE `row` = ? AND `column` = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setInt(1, position.getRowIndex()); + preparedStatement.setString(2, position.getColumn().name()); + preparedStatement.executeUpdate(); + }); + } + + @Override + public Piece findPieceByPosition(Position position) { + List pieces = new ArrayList<>(); + final String query = "SELECT piece_type, piece_color FROM board WHERE `row` = ? AND `column` = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setInt(1, position.getRowIndex()); + preparedStatement.setString(2, position.getColumn().name()); + ResultSet rs = preparedStatement.executeQuery(); + if (rs.next()) { + pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); + } + }); + return pieces.get(0); + } + + @Override + public List findPieceByColor(Color piece_color) { + List pieces = new ArrayList<>(); + String query = "SELECT piece_type, piece_color FROM board WHERE piece_color = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, piece_color.name()); + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + Piece piece = new Piece(rs.getString("piece_type"), rs.getString("piece_color")); + pieces.add(piece); + } + }); + return pieces; + } + + @Override + public List getPieceCountByPieceType(PieceType pieceType) { + List pieceCount = new ArrayList<>(); + String query = "SELECT COUNT(*) AS piece_count FROM board WHERE piece_type = ? GROUP BY `column`"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, pieceType.name()); + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + pieceCount.add(rs.getInt("piece_count")); + } + }); + return pieceCount; + } + + @Override + public Map findAllPiece() { + Map allPieces = new HashMap<>(); + String query = "SELECT * FROM board"; + processQuery(query, preparedStatement -> { + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + Position position = new Position(rs.getInt("row"), rs.getString("column")); + Piece piece = new Piece(rs.getString("piece_type"), rs.getString("piece_color")); + allPieces.put(position, piece); + } + }); + return allPieces; + } + + @Override + public List findPieceByPieceType(PieceType pieceType) { + List pieces = new ArrayList<>(); + final String query = "SELECT piece_type, piece_color FROM board WHERE piece_type = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, pieceType.name()); + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); + } + }); + return pieces; + } + + private void processQuery(String query, QueryProcessor queryProcessor) { + try (final Connection connection = dbConnection.getConnection()) { + final PreparedStatement preparedStatement = connection.prepareStatement(query); + queryProcessor.process(preparedStatement); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/chess/repository/DBConnection.java b/src/main/java/chess/repository/DBConnection.java new file mode 100644 index 00000000000..56679105a55 --- /dev/null +++ b/src/main/java/chess/repository/DBConnection.java @@ -0,0 +1,23 @@ +package chess.repository; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class DBConnection { + + private static final String SERVER = "localhost:3306"; + private static final String DATABASE = "chess"; + private static final String OPTION = "?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + private static final String USERNAME = "root"; + private static final String PASSWORD = "99113030"; + + public Connection getConnection() { + try { + return DriverManager.getConnection("jdbc:mysql://" + SERVER + "/" + DATABASE + OPTION, USERNAME, PASSWORD); + } catch (SQLException e) { + System.out.println("DB 연결 오류:" + e.getMessage()); + throw new RuntimeException("데이터베이스 연결에 실패했습니다."); + } + } +} diff --git a/src/main/java/chess/repository/QueryProcessor.java b/src/main/java/chess/repository/QueryProcessor.java new file mode 100644 index 00000000000..8375d02c69c --- /dev/null +++ b/src/main/java/chess/repository/QueryProcessor.java @@ -0,0 +1,10 @@ +package chess.repository; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +@FunctionalInterface +public interface QueryProcessor { + + void process(PreparedStatement preparedStatement) throws SQLException; +} diff --git a/src/test/java/chess/domain/mock/BlackPieceRepository.java b/src/test/java/chess/domain/mock/BlackPieceRepository.java new file mode 100644 index 00000000000..16333b38c3f --- /dev/null +++ b/src/test/java/chess/domain/mock/BlackPieceRepository.java @@ -0,0 +1,50 @@ +package chess.domain.mock; + +import chess.domain.board.position.Position; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.repository.BoardRepository; +import java.util.List; +import java.util.Map; + +public class BlackPieceRepository implements BoardRepository { + + @Override + public void savePiece(Piece piece, Position position) { + } + + @Override + public boolean existsPieceByPosition(Position position) { + return true; + } + + @Override + public void deletePieceByPosition(Position position) { + } + + @Override + public Piece findPieceByPosition(Position position) { + return new Piece(PieceType.BLACK_PAWN, Color.BLACK); + } + + @Override + public List findPieceByColor(Color color) { + return null; + } + + @Override + public List getPieceCountByPieceType(PieceType pieceType) { + return null; + } + + @Override + public Map findAllPiece() { + return null; + } + + @Override + public List findPieceByPieceType(PieceType pieceType) { + return null; + } +} diff --git a/src/test/java/chess/domain/mock/NotExistsPieceRepository.java b/src/test/java/chess/domain/mock/NotExistsPieceRepository.java new file mode 100644 index 00000000000..b815827a851 --- /dev/null +++ b/src/test/java/chess/domain/mock/NotExistsPieceRepository.java @@ -0,0 +1,48 @@ +package chess.domain.mock; + +import chess.domain.board.position.Position; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.repository.BoardRepository; +import java.util.List; +import java.util.Map; + +public class NotExistsPieceRepository implements BoardRepository { + + @Override + public void savePiece(Piece piece, Position position) {} + + @Override + public boolean existsPieceByPosition(Position position) { + return false; + } + + @Override + public void deletePieceByPosition(Position position) {} + + @Override + public Piece findPieceByPosition(Position position) { + return null; + } + + @Override + public List findPieceByColor(Color color) { + return null; + } + + @Override + public List getPieceCountByPieceType(PieceType pieceType) { + return null; + } + + @Override + public Map findAllPiece() { + return null; + } + + @Override + public List findPieceByPieceType(PieceType pieceType) { + return null; + } +} diff --git a/src/test/java/chess/domain/mock/WhitePieceRepository.java b/src/test/java/chess/domain/mock/WhitePieceRepository.java new file mode 100644 index 00000000000..58c9548ee00 --- /dev/null +++ b/src/test/java/chess/domain/mock/WhitePieceRepository.java @@ -0,0 +1,48 @@ +package chess.domain.mock; + +import chess.domain.board.position.Position; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.repository.BoardRepository; +import java.util.List; +import java.util.Map; + +public class WhitePieceRepository implements BoardRepository { + + @Override + public void savePiece(Piece piece, Position position) {} + + @Override + public boolean existsPieceByPosition(Position position) { + return true; + } + + @Override + public void deletePieceByPosition(Position position) {} + + @Override + public Piece findPieceByPosition(Position position) { + return new Piece(PieceType.WHITE_PAWN, Color.WHITE); + } + + @Override + public List findPieceByColor(Color color) { + return null; + } + + @Override + public List getPieceCountByPieceType(PieceType pieceType) { + return null; + } + + @Override + public Map findAllPiece() { + return null; + } + + @Override + public List findPieceByPieceType(PieceType pieceType) { + return null; + } +} diff --git a/src/test/java/chess/domain/positionFilter/BishopTest.java b/src/test/java/chess/domain/positionFilter/BishopTest.java index 118acdea67d..af2ae6114cb 100644 --- a/src/test/java/chess/domain/positionFilter/BishopTest.java +++ b/src/test/java/chess/domain/positionFilter/BishopTest.java @@ -2,51 +2,86 @@ import static org.assertj.core.api.Assertions.assertThat; -import chess.domain.board.Board; import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; +import chess.domain.mock.BlackPieceRepository; +import chess.domain.mock.NotExistsPieceRepository; +import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.List; import java.util.Map; +import java.util.Queue; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class BishopTest { - /** - * ........ 8 (rank 8) - * ........ 7 - * ........ 6 - * ........ 5 - * ........ 4 - * ....P... 3 - * .p...... 2 - * ..b..... 1 (rank 1) - * - * abcdefgh - */ + @Test - @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") - void generateMovablePositions() { - Position position = new Position(Row.ONE, Column.C); + @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") + void startPositionPawnWithOnlyAttackPossiblePositions() { Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.TWO, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.THREE, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK) - ) + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.E), + new Position(Row.SEVEN, Column.F), + new Position(Row.EIGHT, Column.G), + + new Position(Row.FOUR, Column.E), + new Position(Row.THREE, Column.F), + new Position(Row.TWO, Column.G), + new Position(Row.ONE, Column.H), + + new Position(Row.FOUR, Column.C), + new Position(Row.THREE, Column.B), + new Position(Row.TWO, Column.A), + + new Position(Row.SIX, Column.C), + new Position(Row.SEVEN, Column.B), + new Position(Row.EIGHT, Column.A) ); + } - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); + @Test + @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") + void startPositionPawnWithFreePositions() { + Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.TWO, Column.D), - new Position(Row.THREE, Column.E) + new Position(Row.SIX, Column.E), + new Position(Row.FOUR, Column.E), + new Position(Row.FOUR, Column.C), + new Position(Row.SIX, Column.C) ); } + + @Test + @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") + void startPositionPawnWithCantMovePositions() { + Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).isEmpty(); + } } diff --git a/src/test/java/chess/domain/positionFilter/BlackPawnTest.java b/src/test/java/chess/domain/positionFilter/BlackPawnTest.java deleted file mode 100644 index 2ab182b407c..00000000000 --- a/src/test/java/chess/domain/positionFilter/BlackPawnTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package chess.domain.positionFilter; - -import static org.assertj.core.api.Assertions.assertThat; - -import chess.domain.board.Board; -import chess.domain.board.position.Column; -import chess.domain.board.position.Position; -import chess.domain.board.position.Row; -import chess.domain.game.PositionsFilter; -import chess.domain.piece.Color; -import chess.domain.piece.Piece; -import chess.domain.piece.PieceType; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class BlackPawnTest { - /** - * ........ 8 (rank 8) - * ...P.... 7 - * ..r.r... 6 - * ........ 5 - * ........ 4 - * ........ 3 - * ........ 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ - @Test - @DisplayName("블랙 폰 시작 위치에서 양쪽 대각선에 상대 기물이 있고 앞 2칸은 비어있다.") - void startPositionPawnWithOnlyAttackablePositions() { - Position position = new Position(Row.SEVEN, Column.D); - Piece piece = new Piece(PieceType.BLACK_PAWN, Color.BLACK); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.SIX, Column.C), new Piece(PieceType.ROOK, Color.WHITE), - new Position(Row.SIX, Column.E), new Piece(PieceType.ROOK, Color.WHITE) - ) - ); - - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); - - assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.SIX, Column.C), - new Position(Row.SIX, Column.E), - new Position(Row.SIX, Column.D), - new Position(Row.FIVE, Column.D) - ); - } - - /** - * ........ 8 (rank 8) - * ...P.... 7 - * ..P..... 6 - * ........ 5 - * ........ 4 - * ........ 3 - * ........ 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ - @Test - @DisplayName("블랙 폰 시작 위치에서 앞으로만 이동할 수 있는 경우") - void startPositionPawnWithFreePositions() { - Position position = new Position(Row.SEVEN, Column.D); - Piece piece = new Piece(PieceType.BLACK_PAWN, Color.BLACK); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.SIX, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK) - ) - ); - - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); - - assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.SIX, Column.D), - new Position(Row.FIVE, Column.D) - ); - } - - /** - * ........ 8 (rank 8) - * ...P.... 7 - * ..Pp.... 6 - * ........ 5 - * ........ 4 - * ........ 3 - * ........ 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ - @Test - @DisplayName("블랙 폰 시작 위치에서 움직일 수 없는 경우") - void startPositionPawnWithCantMovePositions() { - Position position = new Position(Row.SEVEN, Column.D); - Piece piece = new Piece(PieceType.BLACK_PAWN, Color.BLACK); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.SIX, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.SIX, Column.D), new Piece(PieceType.BLACK_PAWN, Color.WHITE) - ) - ); - - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); - - assertThat(movablePositions).isEmpty(); - } -} diff --git a/src/test/java/chess/domain/positionFilter/KingTest.java b/src/test/java/chess/domain/positionFilter/KingTest.java index 055f06da45c..6a35fbcb1fc 100644 --- a/src/test/java/chess/domain/positionFilter/KingTest.java +++ b/src/test/java/chess/domain/positionFilter/KingTest.java @@ -2,61 +2,82 @@ import static org.assertj.core.api.Assertions.assertThat; -import chess.domain.board.Board; import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; +import chess.domain.mock.BlackPieceRepository; +import chess.domain.mock.NotExistsPieceRepository; +import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.List; import java.util.Map; +import java.util.Queue; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class KingTest { - /** - * ........ 8 (rank 8) - * ...P.... 7 - * ........ 6 - * ........ 5 - * .....P.. 4 - * ..p..... 3 - * ..Pkp... 2 - * ..NbR... 1 (rank 1) - * - * abcdefgh - */ + @Test - @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") - void generateMovablePositions() { - Position position = new Position(Row.TWO, Column.D); + @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") + void startPositionPawnWithOnlyAttackPossiblePositions() { Piece piece = new Piece(PieceType.KING, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.TWO, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.ONE, Column.D), new Piece(PieceType.BISHOP, Color.WHITE), - new Position(Row.THREE, Column.C), new Piece(PieceType.BLACK_PAWN, Color.WHITE), - new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.FOUR, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.ONE, Column.E), new Piece(PieceType.ROOK, Color.BLACK), - new Position(Row.ONE, Column.C), new Piece(PieceType.KNIGHT, Color.BLACK), - new Position(Row.TWO, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK) - - ) + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.D), + new Position(Row.SIX, Column.E), + new Position(Row.FIVE, Column.E), + new Position(Row.FOUR, Column.E), + new Position(Row.FOUR, Column.D), + new Position(Row.FOUR, Column.C), + new Position(Row.FIVE, Column.C), + new Position(Row.SIX, Column.C) ); + } + + @Test + @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") + void startPositionPawnWithFreePositions() { + Piece piece = new Piece(PieceType.KING, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), + candidateAllPositions); - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); + List movablePositions = positionsFilter.generateValidPositions(piece); assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.THREE, Column.D), - new Position(Row.THREE, Column.E), - new Position(Row.ONE, Column.E), - new Position(Row.ONE, Column.C), - new Position(Row.TWO, Column.C) + new Position(Row.SIX, Column.D), + new Position(Row.SIX, Column.E), + new Position(Row.FIVE, Column.E), + new Position(Row.FOUR, Column.E), + new Position(Row.FOUR, Column.D), + new Position(Row.FOUR, Column.C), + new Position(Row.FIVE, Column.C), + new Position(Row.SIX, Column.C) ); } + + @Test + @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") + void startPositionPawnWithCantMovePositions() { + Piece piece = new Piece(PieceType.KING, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).isEmpty(); + } } diff --git a/src/test/java/chess/domain/positionFilter/KnightTest.java b/src/test/java/chess/domain/positionFilter/KnightTest.java index f0b2cef5e10..a1f27d1bff6 100644 --- a/src/test/java/chess/domain/positionFilter/KnightTest.java +++ b/src/test/java/chess/domain/positionFilter/KnightTest.java @@ -2,62 +2,82 @@ import static org.assertj.core.api.Assertions.assertThat; -import chess.domain.board.Board; import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; +import chess.domain.mock.BlackPieceRepository; +import chess.domain.mock.NotExistsPieceRepository; +import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.List; import java.util.Map; +import java.util.Queue; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class KnightTest { - /** - * ........ 8 (rank 8) - * ........ 7 - * ..r.P... 6 - * ..P.P... 5 - * ...np... 4 - * .B.ppq.. 3 - * ........ 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ + @Test - @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") - void generateMovablePositions() { - Position position = new Position(Row.FOUR, Column.D); + @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") + void startPositionPawnWithOnlyAttackPossiblePositions() { Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.THREE, Column.F), new Piece(PieceType.QUEEN, Color.WHITE), - new Position(Row.SIX, Column.C), new Piece(PieceType.ROOK, Color.WHITE), - new Position(Row.FOUR, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.THREE, Column.D), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.THREE, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.SIX, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.FIVE, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.FIVE, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.THREE, Column.B), new Piece(PieceType.BISHOP, Color.BLACK) - ) + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SEVEN, Column.C), + new Position(Row.SEVEN, Column.E), + new Position(Row.SIX, Column.F), + new Position(Row.FOUR, Column.F), + new Position(Row.THREE, Column.E), + new Position(Row.THREE, Column.C), + new Position(Row.SIX, Column.B), + new Position(Row.FOUR, Column.B) ); + } + + @Test + @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") + void startPositionPawnWithFreePositions() { + Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), + candidateAllPositions); - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); + List movablePositions = positionsFilter.generateValidPositions(piece); assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.SIX, Column.E), - new Position(Row.FIVE, Column.F), - new Position(Row.TWO, Column.E), - new Position(Row.TWO, Column.C), - new Position(Row.THREE, Column.B), - new Position(Row.FIVE, Column.B) + new Position(Row.SEVEN, Column.C), + new Position(Row.SEVEN, Column.E), + new Position(Row.SIX, Column.F), + new Position(Row.FOUR, Column.F), + new Position(Row.THREE, Column.E), + new Position(Row.THREE, Column.C), + new Position(Row.SIX, Column.B), + new Position(Row.FOUR, Column.B) ); } + + @Test + @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") + void startPositionPawnWithCantMovePositions() { + Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).isEmpty(); + } } diff --git a/src/test/java/chess/domain/positionFilter/PawnTest.java b/src/test/java/chess/domain/positionFilter/PawnTest.java new file mode 100644 index 00000000000..06af5f4b86d --- /dev/null +++ b/src/test/java/chess/domain/positionFilter/PawnTest.java @@ -0,0 +1,71 @@ +package chess.domain.positionFilter; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.game.PositionsFilter; +import chess.domain.mock.BlackPieceRepository; +import chess.domain.mock.NotExistsPieceRepository; +import chess.domain.mock.WhitePieceRepository; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PawnTest { + + @Test + @DisplayName("시작 위치 앞 2칸이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") + void startPositionPawnWithOnlyAttackPossiblePositions() { + Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); + Position position = new Position(Row.TWO, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.THREE, Column.D), + new Position(Row.FOUR, Column.D) + ); + } + + @Test + @DisplayName("대각선에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") + void startPositionPawnWithFreePositions() { + Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); + Position position = new Position(Row.TWO, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.THREE, Column.C), + new Position(Row.THREE, Column.E) + ); + } + + @Test + @DisplayName("앞에 기물이 존재하고 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") + void startPositionPawnWithCantMovePositions() { + Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); + Position position = new Position(Row.TWO, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).isEmpty(); + } +} diff --git a/src/test/java/chess/domain/positionFilter/QueenTest.java b/src/test/java/chess/domain/positionFilter/QueenTest.java index e2d557aba27..cd45fbde0eb 100644 --- a/src/test/java/chess/domain/positionFilter/QueenTest.java +++ b/src/test/java/chess/domain/positionFilter/QueenTest.java @@ -2,67 +2,108 @@ import static org.assertj.core.api.Assertions.assertThat; -import chess.domain.board.Board; import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; +import chess.domain.mock.BlackPieceRepository; +import chess.domain.mock.NotExistsPieceRepository; +import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.List; import java.util.Map; +import java.util.Queue; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class QueenTest { - /** - * ........ 8 (rank 8) - * ...P.... 7 - * ........ 6 - * ........ 5 - * .....P.. 4 - * ..p..... 3 - * ..Pqp... 2 - * ..NkR... 1 (rank 1) - * - * abcdefgh - */ @Test - @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") - void generateMovablePositions() { - Position position = new Position(Row.TWO, Column.D); + @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") + void startPositionPawnWithOnlyAttackPossiblePositions() { Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.TWO, Column.E), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.ONE, Column.D), new Piece(PieceType.KING, Color.WHITE), - new Position(Row.THREE, Column.C), new Piece(PieceType.BLACK_PAWN, Color.WHITE), - new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.FOUR, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK), - new Position(Row.ONE, Column.E), new Piece(PieceType.ROOK, Color.BLACK), - new Position(Row.ONE, Column.C), new Piece(PieceType.KNIGHT, Color.BLACK), - new Position(Row.TWO, Column.C), new Piece(PieceType.BLACK_PAWN, Color.BLACK) - - ) - ); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), + candidateAllPositions); - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); + List movablePositions = positionsFilter.generateValidPositions(piece); assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.THREE, Column.D), - new Position(Row.FOUR, Column.D), - new Position(Row.FIVE, Column.D), + new Position(Row.SIX, Column.E), + new Position(Row.SEVEN, Column.F), + new Position(Row.EIGHT, Column.G), + + new Position(Row.FOUR, Column.E), + new Position(Row.THREE, Column.F), + new Position(Row.TWO, Column.G), + new Position(Row.ONE, Column.H), + + new Position(Row.FOUR, Column.C), + new Position(Row.THREE, Column.B), + new Position(Row.TWO, Column.A), + + new Position(Row.SIX, Column.C), + new Position(Row.SEVEN, Column.B), + new Position(Row.EIGHT, Column.A), + new Position(Row.SIX, Column.D), new Position(Row.SEVEN, Column.D), - new Position(Row.THREE, Column.E), - new Position(Row.FOUR, Column.F), - new Position(Row.ONE, Column.E), - new Position(Row.ONE, Column.C), - new Position(Row.TWO, Column.C) + new Position(Row.EIGHT, Column.D), + + new Position(Row.FIVE, Column.E), + new Position(Row.FIVE, Column.F), + new Position(Row.FIVE, Column.G), + new Position(Row.FIVE, Column.H), + + new Position(Row.FOUR, Column.D), + new Position(Row.THREE, Column.D), + new Position(Row.TWO, Column.D), + new Position(Row.ONE, Column.D), + + new Position(Row.FIVE, Column.C), + new Position(Row.FIVE, Column.B), + new Position(Row.FIVE, Column.A) + ); + } + + @Test + @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") + void startPositionPawnWithFreePositions() { + Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.E), + new Position(Row.FOUR, Column.E), + new Position(Row.FOUR, Column.C), + new Position(Row.SIX, Column.C), + new Position(Row.SIX, Column.D), + new Position(Row.FIVE, Column.E), + new Position(Row.FOUR, Column.D), + new Position(Row.FIVE, Column.C) ); } + + @Test + @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") + void startPositionPawnWithCantMovePositions() { + Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).isEmpty(); + } } diff --git a/src/test/java/chess/domain/positionFilter/RookTest.java b/src/test/java/chess/domain/positionFilter/RookTest.java index 6dd24fea2fa..0e7fec0fd34 100644 --- a/src/test/java/chess/domain/positionFilter/RookTest.java +++ b/src/test/java/chess/domain/positionFilter/RookTest.java @@ -2,57 +2,87 @@ import static org.assertj.core.api.Assertions.assertThat; -import chess.domain.board.Board; import chess.domain.board.position.Column; +import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; +import chess.domain.mock.BlackPieceRepository; +import chess.domain.mock.NotExistsPieceRepository; +import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import java.util.List; import java.util.Map; +import java.util.Queue; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class RookTest { - /** - * ........ 8 (rank 8) - * ........ 7 - * ...B.... 6 - * .n.Rr... 5 - * ...r.... 4 - * ........ 3 - * ........ 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ @Test - @DisplayName("실제로 움직일 수 있는 위치를 모두 가져온다.") - void generateMovablePositions() { + @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") + void startPositionPawnWithOnlyAttackPossiblePositions() { + Piece piece = new Piece(PieceType.ROOK, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); - Piece piece = new Piece(PieceType.ROOK, Color.BLACK); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.FOUR, Column.D), new Piece(PieceType.ROOK, Color.WHITE), - new Position(Row.FIVE, Column.E), new Piece(PieceType.ROOK, Color.WHITE), - new Position(Row.FIVE, Column.B), new Piece(PieceType.KNIGHT, Color.WHITE), - new Position(Row.SIX, Column.D), new Piece(PieceType.BISHOP, Color.BLACK) - ) - ); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), + candidateAllPositions); - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); + List movablePositions = positionsFilter.generateValidPositions(piece); assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.FOUR, Column.D), + new Position(Row.SIX, Column.D), + new Position(Row.SEVEN, Column.D), + new Position(Row.EIGHT, Column.D), + new Position(Row.FIVE, Column.E), + new Position(Row.FIVE, Column.F), + new Position(Row.FIVE, Column.G), + new Position(Row.FIVE, Column.H), + + new Position(Row.FOUR, Column.D), + new Position(Row.THREE, Column.D), + new Position(Row.TWO, Column.D), + new Position(Row.ONE, Column.D), + + new Position(Row.FIVE, Column.C), new Position(Row.FIVE, Column.B), + new Position(Row.FIVE, Column.A) + ); + } + + @Test + @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") + void startPositionPawnWithFreePositions() { + Piece piece = new Piece(PieceType.ROOK, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).containsExactlyInAnyOrder( + new Position(Row.SIX, Column.D), + new Position(Row.FIVE, Column.E), + new Position(Row.FOUR, Column.D), new Position(Row.FIVE, Column.C) ); } + @Test + @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") + void startPositionPawnWithCantMovePositions() { + Piece piece = new Piece(PieceType.ROOK, Color.WHITE); + Position position = new Position(Row.FIVE, Column.D); + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), + candidateAllPositions); + + List movablePositions = positionsFilter.generateValidPositions(piece); + + assertThat(movablePositions).isEmpty(); + } } diff --git a/src/test/java/chess/domain/positionFilter/WhitePawnTest.java b/src/test/java/chess/domain/positionFilter/WhitePawnTest.java deleted file mode 100644 index d94556ca33a..00000000000 --- a/src/test/java/chess/domain/positionFilter/WhitePawnTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package chess.domain.positionFilter; - -import static org.assertj.core.api.Assertions.assertThat; - -import chess.domain.board.Board; -import chess.domain.board.position.Column; -import chess.domain.board.position.Position; -import chess.domain.board.position.Row; -import chess.domain.game.PositionsFilter; -import chess.domain.piece.Color; -import chess.domain.piece.Piece; -import chess.domain.piece.PieceType; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class WhitePawnTest { - /** - * ........ 8 (rank 8) - * ........ 7 - * ........ 6 - * ........ 5 - * ........ 4 - * ..R.R... 3 - * ...p.... 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ - @Test - @DisplayName("화이트 폰 시작 위치에서 양쪽 대각선에 상대 기물이 있고 앞 2칸은 비어있다.") - void startPositionPawnWithOnlyAttackablePositions() { - Position position = new Position(Row.TWO, Column.D); - Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.THREE, Column.C), new Piece(PieceType.ROOK, Color.BLACK), - new Position(Row.THREE, Column.E), new Piece(PieceType.ROOK, Color.BLACK) - ) - ); - - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); - - assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.THREE, Column.C), - new Position(Row.THREE, Column.E), - new Position(Row.THREE, Column.D), - new Position(Row.FOUR, Column.D) - ); - } - - /** - * ........ 8 (rank 8) - * ........ 7 - * ........ 6 - * ........ 5 - * ........ 4 - * ..p..... 3 - * ...p.... 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ - @Test - @DisplayName("화이트 폰 시작 위치에서 앞으로만 이동할 수 있는 경우") - void startPositionPawnWithFreePositions() { - Position position = new Position(Row.TWO, Column.D); - Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.THREE, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE) - ) - ); - - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); - - assertThat(movablePositions).containsExactlyInAnyOrder( - new Position(Row.THREE, Column.D), - new Position(Row.FOUR, Column.D) - ); - } - - /** - * ........ 8 (rank 8) - * ........ 7 - * ........ 6 - * ........ 5 - * ........ 4 - * ..pP.... 3 - * ...p.... 2 - * ........ 1 (rank 1) - * - * abcdefgh - */ - @Test - @DisplayName("화이트 폰 시작 위치에서 움직일 수 없는 경우") - void startPositionPawnWithCantMovePositions() { - Position position = new Position(Row.TWO, Column.D); - Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); - Board board = new Board( - Map.of( - position, piece, - new Position(Row.THREE, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE), - new Position(Row.THREE, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK) - ) - ); - - List movablePositions = new PositionsFilter().generateValidPositions( - piece.generateAllDirectionPositions(position), piece, board); - - assertThat(movablePositions).isEmpty(); - } -} From 19d005c3689da3523a9c7e3bef4ab3e3cd90ba2a Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 22:21:49 +0900 Subject: [PATCH 09/18] =?UTF-8?q?feat(Room):=20=EC=B2=B4=EC=8A=A4=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EB=B0=A9=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?Room=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/domain/game/Room.java | 20 +++++++++++++++ src/main/java/chess/domain/game/RoomName.java | 17 +++++++++++++ .../java/chess/domain/game/RoomNameTest.java | 25 +++++++++++++++++++ .../domain/positionFilter/BishopTest.java | 12 ++++----- 4 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/main/java/chess/domain/game/Room.java create mode 100644 src/main/java/chess/domain/game/RoomName.java create mode 100644 src/test/java/chess/domain/game/RoomNameTest.java diff --git a/src/main/java/chess/domain/game/Room.java b/src/main/java/chess/domain/game/Room.java new file mode 100644 index 00000000000..398d296bbd1 --- /dev/null +++ b/src/main/java/chess/domain/game/Room.java @@ -0,0 +1,20 @@ +package chess.domain.game; + +public class Room { + + private final Long id; + private final RoomName roomName; + + public Room(Long id, String name) { + this.id = id; + this.roomName = new RoomName(name); + } + + public String getName() { + return roomName.getValue(); + } + + public Long getId() { + return id; + } +} diff --git a/src/main/java/chess/domain/game/RoomName.java b/src/main/java/chess/domain/game/RoomName.java new file mode 100644 index 00000000000..d00d66d2bc6 --- /dev/null +++ b/src/main/java/chess/domain/game/RoomName.java @@ -0,0 +1,17 @@ +package chess.domain.game; + +public class RoomName { + + private final String name; + + public RoomName(String name) { + if (name.length() > 16) { + throw new IllegalArgumentException("게임 방 이름 길이는 최대 16글자까지 가능합니다."); + } + this.name = name; + } + + public String getValue() { + return name; + } +} diff --git a/src/test/java/chess/domain/game/RoomNameTest.java b/src/test/java/chess/domain/game/RoomNameTest.java new file mode 100644 index 00000000000..9968159065d --- /dev/null +++ b/src/test/java/chess/domain/game/RoomNameTest.java @@ -0,0 +1,25 @@ +package chess.domain.game; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RoomNameTest { + + @DisplayName("게임방 이름 길이가 16글자 이하면 정상 생성된다.") + @Test + void validateNameLengthSuccessTest() { + assertThatNoException() + .isThrownBy(() -> new RoomName("----------------")); + } + + @DisplayName("게임방 이름 길이가 16글자를 초과하면 에러를 발생시킨다.") + @Test + void validateNameLengthFailTest() { + assertThatThrownBy(() -> new RoomName("-----------------")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("게임 방 이름 길이는 최대 16글자까지 가능합니다."); + } +} diff --git a/src/test/java/chess/domain/positionFilter/BishopTest.java b/src/test/java/chess/domain/positionFilter/BishopTest.java index af2ae6114cb..2e67c0ef71d 100644 --- a/src/test/java/chess/domain/positionFilter/BishopTest.java +++ b/src/test/java/chess/domain/positionFilter/BishopTest.java @@ -23,14 +23,14 @@ class BishopTest { @Test @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") - void startPositionPawnWithOnlyAttackPossiblePositions() { + void positionEmptyAllMovablePositionsIncludedTest() { Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.E), @@ -54,14 +54,14 @@ void startPositionPawnWithOnlyAttackPossiblePositions() { @Test @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") - void startPositionPawnWithFreePositions() { + void positionWithOpponentPiecesTest() { Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.E), @@ -73,14 +73,14 @@ void startPositionPawnWithFreePositions() { @Test @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") - void startPositionPawnWithCantMovePositions() { + void positionWithOwnPiecesTest() { Piece piece = new Piece(PieceType.BISHOP, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).isEmpty(); } From e495e9e82c7f28c672a71e708d9a63fa7c0b36e9 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 22:30:46 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat:=20=EC=B2=B4=EC=8A=A4=20=EC=83=81?= =?UTF-8?q?=ED=99=A9=20=EC=A0=80=EC=9E=A5=20=EB=B0=8F=20=EC=B2=B4=EC=8A=A4?= =?UTF-8?q?=20=EA=B2=8C=EC=9E=84=EB=B0=A9=20=EC=83=9D=EC=84=B1=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +- src/main/java/chess/Application.java | 6 +- .../chess/controller/ChessGameController.java | 37 +++++-- .../chess/controller/command/Command.java | 5 +- .../controller/command/CommandRouter.java | 2 +- .../java/chess/controller/command/End.java | 5 +- .../java/chess/controller/command/Move.java | 21 ++-- .../java/chess/controller/command/Start.java | 11 +- .../java/chess/controller/command/Status.java | 11 +- .../chess/domain/board/position/Position.java | 8 ++ .../java/chess/domain/board/position/Row.java | 4 + .../java/chess/domain/game/ChessGame.java | 69 ------------ .../chess/domain/game/PositionsFilter.java | 37 ++++--- src/main/java/chess/domain/game/Score.java | 12 ++- src/main/java/chess/domain/game/Winner.java | 10 +- src/main/java/chess/domain/piece/Piece.java | 11 +- .../java/chess/domain/piece/PieceType.java | 8 -- .../chess/repository/BoardRepository.java | 16 +-- .../chess/repository/BoardRepositoryImpl.java | 40 ++++--- .../java/chess/repository/RoomRepository.java | 21 ++++ .../chess/repository/RoomRepositoryImpl.java | 101 ++++++++++++++++++ src/main/java/chess/service/BoardService.java | 67 ++++++++++++ src/main/java/chess/service/GameService.java | 91 ++++++++++++++++ .../game => service/dto}/ChessGameResult.java | 4 +- src/main/java/chess/view/InputView.java | 4 + src/main/java/chess/view/OutputView.java | 73 +++++++++---- .../java/chess/view/mapper/RowMapper.java | 24 ++--- .../controller/command/CommandRouterTest.java | 2 +- .../chess/controller/command/EndTest.java | 8 +- .../chess/controller/command/MoveTest.java | 25 ++--- .../chess/controller/command/StartTest.java | 9 +- .../chess/controller/command/StatusTest.java | 9 +- .../java/chess/domain/board/BoardTest.java | 52 --------- src/test/java/chess/domain/board/RowTest.java | 36 +++++-- .../java/chess/domain/game/WinnerTest.java | 8 +- .../domain/mock/BlackPieceRepository.java | 16 +-- .../domain/mock/NotExistsPieceRepository.java | 18 ++-- .../domain/mock/WhitePieceRepository.java | 18 ++-- .../chess/domain/positionFilter/KingTest.java | 12 +-- .../domain/positionFilter/KnightTest.java | 12 +-- .../chess/domain/positionFilter/PawnTest.java | 12 +-- .../domain/positionFilter/QueenTest.java | 12 +-- .../chess/domain/positionFilter/RookTest.java | 12 +-- .../java/chess/view/mapper/RowMapperTest.java | 15 --- 44 files changed, 617 insertions(+), 368 deletions(-) delete mode 100644 src/main/java/chess/domain/game/ChessGame.java create mode 100644 src/main/java/chess/repository/RoomRepository.java create mode 100644 src/main/java/chess/repository/RoomRepositoryImpl.java create mode 100644 src/main/java/chess/service/BoardService.java create mode 100644 src/main/java/chess/service/GameService.java rename src/main/java/chess/{domain/game => service/dto}/ChessGameResult.java (83%) delete mode 100644 src/test/java/chess/domain/board/BoardTest.java diff --git a/README.md b/README.md index 9695d995e70..3543b7541ef 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,20 @@ # 기능 구현 목록 ## 체스 게임 -- [X] : 체스 게임 시작 문구를 출력한다. +- [X] : 체스 게임 시작 문구를 출력한다. +- [X] : 사용자는 체스 게임 방을 생성할 수 있다. +- [X] : 체스 게임 방 목록중 원하는 방을 선택해서 게임을 시작할 수 있다. - [X] : 시작 명령어를 입력 받는다. - - [X] : start, end 가 아니면 예외를 터트린다. + - [X] : 명령어 형식이 올바르지 않으면 예외를 터트리고 재입력 받는다. - [X] : start 입력 시 게임을 시작한다. - [X] : end 입력 시 게임을 종료한다. - - [ ] : status 입력 시 각 팀의 점수와 어느 팀이 우세한지 출력한다 + - [X] : status 입력 시 각 팀의 점수와 어느 팀이 우세한지 출력한다. + - [X] : move 명령어를 통해 기물을 움직일 수 있다. - [X] : 보드판을 초기화한다. - [X] : 소문자, 대문자로 팀을 구분한다. - [X] : 각 팀은 총 16개의 말을 갖는다. - [X] : 폰 8개, 룩 2개, 나이트 2개, 비숍 2개, 퀸 1개, 킹 1개 -- [X] : 사용자는 보드판에서 위치로 기물을 조회하여 기물을 이동시킬 수 있다. +- [X] : 왕이 잡히면 게임이 종료되고 게임 결과를 출력한다. ## 체스 기물 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 80af2703622..40fd9939255 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -1,10 +1,14 @@ package chess; import chess.controller.ChessGameController; +import chess.service.BoardService; +import chess.service.GameService; public class Application { public static void main(String[] args) { - ChessGameController chessGameController = new ChessGameController(); + GameService gameService = new GameService(); + BoardService boardService = new BoardService(); + ChessGameController chessGameController = new ChessGameController(gameService, boardService); chessGameController.run(); } } diff --git a/src/main/java/chess/controller/ChessGameController.java b/src/main/java/chess/controller/ChessGameController.java index c449906eb68..94deab6a7e0 100644 --- a/src/main/java/chess/controller/ChessGameController.java +++ b/src/main/java/chess/controller/ChessGameController.java @@ -2,29 +2,50 @@ import chess.controller.command.Command; import chess.controller.command.CommandRouter; -import chess.domain.game.ChessGame; +import chess.domain.game.Room; +import chess.service.BoardService; +import chess.service.GameService; import chess.view.InputView; import chess.view.OutputView; public class ChessGameController { + private final GameService gameService; + private final BoardService boardService; + + public ChessGameController(GameService gameService, BoardService boardService) { + this.gameService = gameService; + this.boardService = boardService; + } + public void run() { - ChessGame chessGame = new ChessGame(); - OutputView.printStartMessage(); - process(chessGame); + OutputView.printRoomNames(gameService.findAllRoomNames()); + Room room = createRoom(); + OutputView.printStartMessage(room.getName()); + process(gameService, boardService, room.getId()); + } + + private Room createRoom() { + try { + String input = InputView.readRoomName(); + return gameService.loadRoom(input); + } catch (RuntimeException error) { + OutputView.printError(error); + return createRoom(); + } } - private void process(ChessGame chessGame) { + private void process(GameService gameService, BoardService boardService, Long roomId) { State state = State.RUNNING; do { - state = executeCommand(chessGame, state); + state = executeCommand(gameService, boardService, state, roomId); } while (state != State.END); } - private State executeCommand(ChessGame chessGame, State state) { + private State executeCommand(GameService gameService, BoardService boardService, State state, Long roomId) { try { Command command = CommandRouter.findCommendByInput(InputView.readCommend()); - return command.execute(chessGame); + return command.execute(gameService, boardService, roomId); } catch (RuntimeException error) { OutputView.printError(error); return state; diff --git a/src/main/java/chess/controller/command/Command.java b/src/main/java/chess/controller/command/Command.java index 5d69660fa42..361d66a6aea 100644 --- a/src/main/java/chess/controller/command/Command.java +++ b/src/main/java/chess/controller/command/Command.java @@ -1,9 +1,10 @@ package chess.controller.command; import chess.controller.State; -import chess.domain.game.ChessGame; +import chess.service.BoardService; +import chess.service.GameService; public interface Command { - State execute(ChessGame chessGame); + State execute(GameService gameService, BoardService boardService, Long roomId); } diff --git a/src/main/java/chess/controller/command/CommandRouter.java b/src/main/java/chess/controller/command/CommandRouter.java index 538524184b8..c05e8297058 100644 --- a/src/main/java/chess/controller/command/CommandRouter.java +++ b/src/main/java/chess/controller/command/CommandRouter.java @@ -29,6 +29,6 @@ public static Command findCommendByInput(List commandInput) { .filter(commandRouter -> commandRouter.value.equals(commandInput.get(COMMAND_INDEX))) .map(commandRouter -> commandRouter.command.apply(commandInput)) .findAny() - .orElseThrow(() -> new IllegalArgumentException("옳바르지 않은 명령어 입력입니다.")); + .orElseThrow(() -> new IllegalArgumentException("올바르지 않은 명령어 입력입니다.")); } } diff --git a/src/main/java/chess/controller/command/End.java b/src/main/java/chess/controller/command/End.java index d71193b276e..860b745f4fc 100644 --- a/src/main/java/chess/controller/command/End.java +++ b/src/main/java/chess/controller/command/End.java @@ -1,7 +1,8 @@ package chess.controller.command; import chess.controller.State; -import chess.domain.game.ChessGame; +import chess.service.BoardService; +import chess.service.GameService; import java.util.List; public class End implements Command { @@ -15,7 +16,7 @@ public End(List commandInput) { } @Override - public State execute(ChessGame chessGame) { + public State execute(GameService gameService, BoardService boardService, Long roomId) { return State.END; } } diff --git a/src/main/java/chess/controller/command/Move.java b/src/main/java/chess/controller/command/Move.java index 1e95381ed8e..aa1b012ab49 100644 --- a/src/main/java/chess/controller/command/Move.java +++ b/src/main/java/chess/controller/command/Move.java @@ -4,8 +4,9 @@ import chess.domain.board.position.Column; import chess.domain.board.position.Position; import chess.domain.board.position.Row; -import chess.domain.game.ChessGame; -import chess.domain.game.ChessGameResult; +import chess.service.BoardService; +import chess.service.GameService; +import chess.service.dto.ChessGameResult; import chess.view.OutputView; import chess.view.mapper.ColumnMapper; import chess.view.mapper.RowMapper; @@ -36,20 +37,20 @@ private void validateMoveCommandPattern(List commandInput) { } @Override - public State execute(ChessGame chessGame) { - if (chessGame.isCheckmate(to)) { - ChessGameResult chessGameResult = chessGame.generateGameResult(to); - moveAndPrintBoard(chessGame); + public State execute(GameService gameService, BoardService boardService, Long roomId) { + if (boardService.isCheckmate(to, roomId)) { + moveAndPrintBoard(gameService, boardService, roomId); + ChessGameResult chessGameResult = gameService.generateGameResult(roomId); OutputView.printChessGameResult(chessGameResult); return State.END; } - moveAndPrintBoard(chessGame); + moveAndPrintBoard(gameService, boardService, roomId); return State.RUNNING; } - private void moveAndPrintBoard(ChessGame chessGame) { - chessGame.movePiece(from, to); - OutputView.printBoard(chessGame.getBoard()); + private void moveAndPrintBoard(GameService gameService, BoardService boardService, Long roomId) { + boardService.movePiece(from, to, roomId); + OutputView.printBoard(boardService.getAllPieces(roomId)); } private Position createPosition(String requestColumn, String requestRow) { diff --git a/src/main/java/chess/controller/command/Start.java b/src/main/java/chess/controller/command/Start.java index 2f4a39042d2..5bfe5de70de 100644 --- a/src/main/java/chess/controller/command/Start.java +++ b/src/main/java/chess/controller/command/Start.java @@ -1,23 +1,24 @@ package chess.controller.command; import chess.controller.State; -import chess.domain.game.ChessGame; +import chess.service.BoardService; +import chess.service.GameService; import chess.view.OutputView; import java.util.List; public class Start implements Command { - private static final int START_COMMAND_SIZE = 1; + private static final int END_COMMAND_SIZE = 1; public Start(List commandInput) { - if (commandInput.size() != START_COMMAND_SIZE) { + if (commandInput.size() != END_COMMAND_SIZE) { throw new IllegalArgumentException("게임 시작 명령어 입력 형식이 올바르지 않습니다."); } } @Override - public State execute(ChessGame chessGame) { - OutputView.printBoard(chessGame.getBoard()); + public State execute(GameService gameService, BoardService boardService, Long roomId) { + OutputView.printBoard(boardService.getAllPieces(roomId)); return State.RUNNING; } } diff --git a/src/main/java/chess/controller/command/Status.java b/src/main/java/chess/controller/command/Status.java index 135507803fe..668b5b8941f 100644 --- a/src/main/java/chess/controller/command/Status.java +++ b/src/main/java/chess/controller/command/Status.java @@ -1,12 +1,10 @@ package chess.controller.command; import chess.controller.State; -import chess.domain.game.ChessGame; -import chess.domain.game.Score; -import chess.domain.piece.Color; +import chess.service.BoardService; +import chess.service.GameService; import chess.view.OutputView; import java.util.List; -import java.util.Map; public class Status implements Command { @@ -19,9 +17,8 @@ public Status(List commandInput) { } @Override - public State execute(ChessGame chessGame) { - Map teamScore = chessGame.calculateScore(); - OutputView.printTeamScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); + public State execute(GameService gameService, BoardService boardService, Long roomId) { + OutputView.printTeamScore(gameService.generateGameResult(roomId)); return State.RUNNING; } } diff --git a/src/main/java/chess/domain/board/position/Position.java b/src/main/java/chess/domain/board/position/Position.java index 74ac9ca175f..55a1759d069 100644 --- a/src/main/java/chess/domain/board/position/Position.java +++ b/src/main/java/chess/domain/board/position/Position.java @@ -13,6 +13,10 @@ public Position(Row row, Column column) { this.column = column; } + public Position(int row, String column) { + this(Row.findByIndex(row), Column.valueOf(column)); + } + public Position calculateNextPosition(Direction direction, int weight) { int rowDistance = direction.calculateRowDistance(weight); int columnDistance = direction.calculateColumnDistance(weight); @@ -40,6 +44,10 @@ public int getColumnIndex() { return column.getIndex(); } + public int getRowIndex() { + return row.getIndex(); + } + public Row getRow() { return row; } diff --git a/src/main/java/chess/domain/board/position/Row.java b/src/main/java/chess/domain/board/position/Row.java index 7101a5a8f3c..584989db2da 100644 --- a/src/main/java/chess/domain/board/position/Row.java +++ b/src/main/java/chess/domain/board/position/Row.java @@ -36,4 +36,8 @@ public boolean isNextInRange(int distance) { int nextIndex = index + distance; return EIGHT.index >= nextIndex && nextIndex >= ONE.index; } + + public int getIndex() { + return index; + } } diff --git a/src/main/java/chess/domain/game/ChessGame.java b/src/main/java/chess/domain/game/ChessGame.java deleted file mode 100644 index 12d45f360e4..00000000000 --- a/src/main/java/chess/domain/game/ChessGame.java +++ /dev/null @@ -1,69 +0,0 @@ -package chess.domain.game; - -import chess.domain.board.Board; -import chess.domain.board.BoardFactory; -import chess.domain.board.position.Direction; -import chess.domain.board.position.Position; -import chess.domain.piece.Color; -import chess.domain.piece.Piece; -import java.util.List; -import java.util.Map; -import java.util.Queue; - -public class ChessGame { - - private static final Color START_TURN = Color.WHITE; - - private final Board board; - private Color currentTurn; - - public ChessGame() { - this.board = new Board(new BoardFactory().initialize()); - currentTurn = START_TURN; - } - - public ChessGameResult generateGameResult(Position to) { - Map teamScore = board.calculateScore(); - if (board.isCheckmate(to)) { - Piece king = board.findPieceByPosition(to); - return new ChessGameResult(Winner.selectWinnerByCheckmate(king.getColor()), teamScore); - } - return new ChessGameResult(Winner.selectWinnerByScore(teamScore), teamScore); - } - - public Map calculateScore() { - return board.calculateScore(); - } - - public void movePiece(Position from, Position to) { - validateUserTurn(from); - List movablePositions = generateMovablePositions(from); - if (movablePositions.contains(to)) { - board.movePiece(from, to); - currentTurn = currentTurn.change(); - return; - } - throw new IllegalArgumentException("기물을 해당 위치로 이동시킬 수 없습니다."); - } - - public boolean isCheckmate(Position to) { - return board.isCheckmate(to); - } - - private void validateUserTurn(Position from) { - Piece piece = board.findPieceByPosition(from); - if (piece.isNotSameColor(currentTurn)) { - throw new IllegalArgumentException("상대방의 기물을 움직일 수 없습니다. 현재 턴 : " + currentTurn); - } - } - - private List generateMovablePositions(Position position) { - Piece piece = board.findPieceByPosition(position); - Map> candidateAllPositions = piece.generateAllDirectionPositions(position); - return new PositionsFilter().generateValidPositions(candidateAllPositions, piece, board); - } - - public Board getBoard() { - return board; - } -} diff --git a/src/main/java/chess/domain/game/PositionsFilter.java b/src/main/java/chess/domain/game/PositionsFilter.java index 93813c1512e..a951703220b 100644 --- a/src/main/java/chess/domain/game/PositionsFilter.java +++ b/src/main/java/chess/domain/game/PositionsFilter.java @@ -1,9 +1,9 @@ package chess.domain.game; -import chess.domain.board.Board; import chess.domain.board.position.Direction; import chess.domain.board.position.Position; import chess.domain.piece.Piece; +import chess.repository.BoardRepository; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -11,39 +11,48 @@ public class PositionsFilter { - public List generateValidPositions(Map> candidateAllPositions, - Piece piece, - Board board) { + private final BoardRepository boardRepository; + private final Map> candidateAllPositions; + + public PositionsFilter(BoardRepository boardRepository, + Map> candidateAllPositions) { + this.boardRepository = boardRepository; + this.candidateAllPositions = candidateAllPositions; + } + + public List generateValidPositions(Piece piece, Long roomId) { return candidateAllPositions.keySet().stream() - .map(direction -> filterInvalidPositions(candidateAllPositions.get(direction), direction, piece, board)) + .map(direction -> filterInvalidPositions(candidateAllPositions.get(direction), direction, piece, roomId)) .flatMap(List::stream) .toList(); } - private List filterInvalidPositions(Queue expectedPositions, Direction direction, - Piece piece, Board board) { + private List filterInvalidPositions(Queue expectedPositions, + Direction direction, + Piece piece, + Long roomId) { List result = new ArrayList<>(); Position currentPosition = expectedPositions.poll(); - while (isEmptySpace(direction, piece, currentPosition, board)) { + while (isEmptySpace(direction, piece, currentPosition, roomId)) { result.add(currentPosition); currentPosition = expectedPositions.poll(); } - if (isEnemySpace(direction, piece, currentPosition, board)) { + if (isEnemySpace(direction, piece, currentPosition, roomId)) { result.add(currentPosition); } return result; } - private boolean isEmptySpace(Direction direction, Piece piece, Position currentPosition, Board board) { + private boolean isEmptySpace(Direction direction, Piece piece, Position currentPosition, Long roomId) { return currentPosition != null && piece.isPawnMovePossible(direction) - && board.isEmptySpace(currentPosition); + && !boardRepository.existsPieceByPosition(currentPosition, roomId); } - private boolean isEnemySpace(Direction direction, Piece piece, Position currentPosition, Board board) { + private boolean isEnemySpace(Direction direction, Piece piece, Position currentPosition, Long roomId) { return currentPosition != null && piece.isPawnAttackPossible(direction) - && board.existPiece(currentPosition) - && board.findPieceByPosition(currentPosition).isEnemy(piece); + && boardRepository.existsPieceByPosition(currentPosition, roomId) + && piece.isEnemy(boardRepository.findPieceByPosition(currentPosition, roomId)); } } diff --git a/src/main/java/chess/domain/game/Score.java b/src/main/java/chess/domain/game/Score.java index 9e64f242034..91f1da0ef72 100644 --- a/src/main/java/chess/domain/game/Score.java +++ b/src/main/java/chess/domain/game/Score.java @@ -22,13 +22,15 @@ public Double score() { } @Override - public boolean equals(Object obj) { - if (obj == this) + public boolean equals(Object o) { + if (this == o) { return true; - if (obj == null || obj.getClass() != this.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; - var that = (Score) obj; - return Objects.equals(this.score, that.score); + } + Score score1 = (Score) o; + return Objects.equals(score, score1.score); } @Override diff --git a/src/main/java/chess/domain/game/Winner.java b/src/main/java/chess/domain/game/Winner.java index b1cf31279c6..d11ca02c068 100644 --- a/src/main/java/chess/domain/game/Winner.java +++ b/src/main/java/chess/domain/game/Winner.java @@ -20,14 +20,14 @@ public enum Winner { public static Winner selectWinnerByScore(Map teamScore) { return Arrays.stream(values()) .filter(winner -> winner.selectWinner.test(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK))) - .findFirst() + .findAny() .orElseThrow(IllegalStateException::new); } - public static Winner selectWinnerByCheckmate(Color kingColor) { - if (kingColor == Color.WHITE) { - return BLACK_WIN; + public static Winner selectWinnerByCheckmate(Color aliveKingColor) { + if (aliveKingColor == Color.WHITE) { + return WHITE_WIN; } - return WHITE_WIN; + return BLACK_WIN; } } diff --git a/src/main/java/chess/domain/piece/Piece.java b/src/main/java/chess/domain/piece/Piece.java index 56be9fecea6..45105ed462b 100644 --- a/src/main/java/chess/domain/piece/Piece.java +++ b/src/main/java/chess/domain/piece/Piece.java @@ -16,6 +16,10 @@ public Piece(PieceType pieceType, Color color) { this.color = color; } + public Piece(String pieceType, String color) { + this(PieceType.valueOf(pieceType), Color.valueOf(color)); + } + public Map> generateAllDirectionPositions(Position currentPosition) { return pieceType.generateAllDirectionPositions(currentPosition); } @@ -32,13 +36,6 @@ public boolean isNotSameColor(Color color) { return !isSameColor(color); } - public boolean isPawnByColor(Color color) { - if (color == Color.BLACK) { - return pieceType.isBlackPawn(); - } - return pieceType.isWhitePawn(); - } - public boolean isKing() { return this.pieceType == PieceType.KING; } diff --git a/src/main/java/chess/domain/piece/PieceType.java b/src/main/java/chess/domain/piece/PieceType.java index 277f245774c..ff7becab3f3 100644 --- a/src/main/java/chess/domain/piece/PieceType.java +++ b/src/main/java/chess/domain/piece/PieceType.java @@ -37,12 +37,4 @@ public Map> generateAllDirectionPositions(Position cu public double getScore() { return score; } - - public boolean isBlackPawn() { - return this == BLACK_PAWN; - } - - public boolean isWhitePawn() { - return this == WHITE_PAWN; - } } diff --git a/src/main/java/chess/repository/BoardRepository.java b/src/main/java/chess/repository/BoardRepository.java index f3dfe250e07..ce80531be57 100644 --- a/src/main/java/chess/repository/BoardRepository.java +++ b/src/main/java/chess/repository/BoardRepository.java @@ -9,19 +9,19 @@ public interface BoardRepository { - void savePiece(Piece piece, Position position); + void savePiece(Piece piece, Position position, Long roomId); - boolean existsPieceByPosition(Position position); + boolean existsPieceByPosition(Position position, Long roomId); - void deletePieceByPosition(Position position); + void deletePieceByPosition(Position position, Long roomId); - Piece findPieceByPosition(Position position); + Piece findPieceByPosition(Position position, Long roomId); - List findPieceByColor(Color color); + List findPieceByColor(Color piece_color, Long roomId); - List getPieceCountByPieceType(PieceType pieceType); + List getPieceCountByPieceType(PieceType pieceType, Long roomId); - Map findAllPiece(); + Map findAllPieceByRoomId(Long roomId); - List findPieceByPieceType(PieceType pieceType); + List findPieceByPieceType(PieceType pieceType, Long roomId); } diff --git a/src/main/java/chess/repository/BoardRepositoryImpl.java b/src/main/java/chess/repository/BoardRepositoryImpl.java index c874850245a..daa56d3a3bf 100644 --- a/src/main/java/chess/repository/BoardRepositoryImpl.java +++ b/src/main/java/chess/repository/BoardRepositoryImpl.java @@ -18,25 +18,27 @@ public class BoardRepositoryImpl implements BoardRepository { private final DBConnection dbConnection = new DBConnection(); @Override - public void savePiece(Piece piece, Position position) { - final String query = "INSERT INTO board(`row`, `column`, piece_type, piece_color) VALUES(?, ?, ?, ?)"; + public void savePiece(Piece piece, Position position, Long roomId) { + final String query = "INSERT INTO board(`row`, `column`, piece_type, piece_color, room_id) VALUES(?, ?, ?, ?, ?)"; processQuery(query, preparedStatement -> { preparedStatement.setInt(1, position.getRowIndex()); preparedStatement.setString(2, position.getColumn().name()); preparedStatement.setString(3, piece.getPieceType().name()); preparedStatement.setString(4, piece.getColor().name()); + preparedStatement.setLong(5, roomId); preparedStatement.executeUpdate(); }); } @Override - public boolean existsPieceByPosition(Position position) { + public boolean existsPieceByPosition(Position position, Long roomId) { List existsPiece = new ArrayList<>(); final String query = "SELECT EXISTS (" - + "SELECT 1 FROM board WHERE `row` = ? AND `column` = ?) AS exists_piece"; + + "SELECT 1 FROM board WHERE `row` = ? AND `column` = ? AND room_id = ?) AS exists_piece"; processQuery(query, preparedStatement -> { preparedStatement.setInt(1, position.getRowIndex()); preparedStatement.setString(2, position.getColumn().name()); + preparedStatement.setLong(3, roomId); ResultSet rs = preparedStatement.executeQuery(); if (rs.next()) { existsPiece.add(rs.getBoolean("exists_piece")); @@ -46,22 +48,24 @@ public boolean existsPieceByPosition(Position position) { } @Override - public void deletePieceByPosition(Position position) { - final String query = "DELETE FROM board WHERE `row` = ? AND `column` = ?"; + public void deletePieceByPosition(Position position, Long roomId) { + final String query = "DELETE FROM board WHERE `row` = ? AND `column` = ? AND room_id = ?"; processQuery(query, preparedStatement -> { preparedStatement.setInt(1, position.getRowIndex()); preparedStatement.setString(2, position.getColumn().name()); + preparedStatement.setLong(3, roomId); preparedStatement.executeUpdate(); }); } @Override - public Piece findPieceByPosition(Position position) { + public Piece findPieceByPosition(Position position, Long roomId) { List pieces = new ArrayList<>(); - final String query = "SELECT piece_type, piece_color FROM board WHERE `row` = ? AND `column` = ?"; + final String query = "SELECT piece_type, piece_color FROM board WHERE `row` = ? AND `column` = ? AND room_id = ?"; processQuery(query, preparedStatement -> { preparedStatement.setInt(1, position.getRowIndex()); preparedStatement.setString(2, position.getColumn().name()); + preparedStatement.setLong(3, roomId); ResultSet rs = preparedStatement.executeQuery(); if (rs.next()) { pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); @@ -71,11 +75,12 @@ public Piece findPieceByPosition(Position position) { } @Override - public List findPieceByColor(Color piece_color) { + public List findPieceByColor(Color piece_color, Long roomId) { List pieces = new ArrayList<>(); - String query = "SELECT piece_type, piece_color FROM board WHERE piece_color = ?"; + String query = "SELECT piece_type, piece_color FROM board WHERE piece_color = ? AND room_id = ?"; processQuery(query, preparedStatement -> { preparedStatement.setString(1, piece_color.name()); + preparedStatement.setLong(2, roomId); ResultSet rs = preparedStatement.executeQuery(); while (rs.next()) { Piece piece = new Piece(rs.getString("piece_type"), rs.getString("piece_color")); @@ -86,11 +91,12 @@ public List findPieceByColor(Color piece_color) { } @Override - public List getPieceCountByPieceType(PieceType pieceType) { + public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { List pieceCount = new ArrayList<>(); - String query = "SELECT COUNT(*) AS piece_count FROM board WHERE piece_type = ? GROUP BY `column`"; + String query = "SELECT COUNT(*) AS piece_count FROM board WHERE piece_type = ? AND room_id = ? GROUP BY `column`"; processQuery(query, preparedStatement -> { preparedStatement.setString(1, pieceType.name()); + preparedStatement.setLong(2, roomId); ResultSet rs = preparedStatement.executeQuery(); while (rs.next()) { pieceCount.add(rs.getInt("piece_count")); @@ -100,10 +106,11 @@ public List getPieceCountByPieceType(PieceType pieceType) { } @Override - public Map findAllPiece() { + public Map findAllPieceByRoomId(Long roomId) { Map allPieces = new HashMap<>(); - String query = "SELECT * FROM board"; + String query = "SELECT * FROM board JOIN room ON board.room_id = room.id WHERE board.room_id = ?"; processQuery(query, preparedStatement -> { + preparedStatement.setLong(1, roomId); ResultSet rs = preparedStatement.executeQuery(); while (rs.next()) { Position position = new Position(rs.getInt("row"), rs.getString("column")); @@ -115,11 +122,12 @@ public Map findAllPiece() { } @Override - public List findPieceByPieceType(PieceType pieceType) { + public List findPieceByPieceType(PieceType pieceType, Long roomId) { List pieces = new ArrayList<>(); - final String query = "SELECT piece_type, piece_color FROM board WHERE piece_type = ?"; + final String query = "SELECT piece_type, piece_color FROM board WHERE piece_type = ? AND room_id = ?"; processQuery(query, preparedStatement -> { preparedStatement.setString(1, pieceType.name()); + preparedStatement.setLong(2, roomId); ResultSet rs = preparedStatement.executeQuery(); while (rs.next()) { pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); diff --git a/src/main/java/chess/repository/RoomRepository.java b/src/main/java/chess/repository/RoomRepository.java new file mode 100644 index 00000000000..d473c24d99a --- /dev/null +++ b/src/main/java/chess/repository/RoomRepository.java @@ -0,0 +1,21 @@ +package chess.repository; + +import chess.domain.game.Room; +import chess.domain.game.RoomName; +import chess.domain.piece.Color; +import java.util.List; + +public interface RoomRepository { + + List findAllRoomNames(); + + boolean existsRoomName(RoomName roomName); + + void saveRoom(RoomName roomName); + + void updateRoomTurn(Color color, Long roomId); + + Room findRoomByName(RoomName roomName); + + Color findTurnById(Long roomId); +} diff --git a/src/main/java/chess/repository/RoomRepositoryImpl.java b/src/main/java/chess/repository/RoomRepositoryImpl.java new file mode 100644 index 00000000000..aca205e3815 --- /dev/null +++ b/src/main/java/chess/repository/RoomRepositoryImpl.java @@ -0,0 +1,101 @@ +package chess.repository; + +import chess.domain.game.Room; +import chess.domain.game.RoomName; +import chess.domain.piece.Color; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class RoomRepositoryImpl implements RoomRepository{ + + private final DBConnection dbConnection = new DBConnection(); + + @Override + public List findAllRoomNames() { + List allRoomNames = new ArrayList<>(); + String query = "SELECT name FROM room"; + processQuery(query, preparedStatement -> { + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + allRoomNames.add(rs.getString("name")); + } + }); + return allRoomNames; + } + + @Override + public boolean existsRoomName(RoomName roomName) { + List existsRoom = new ArrayList<>(); + final String query = "SELECT EXISTS (" + + "SELECT 1 FROM room WHERE name = ?) AS exists_room"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, roomName.getValue()); + ResultSet rs = preparedStatement.executeQuery(); + if (rs.next()) { + existsRoom.add(rs.getBoolean("exists_room")); + } + }); + return existsRoom.get(0); + } + + @Override + public void saveRoom(RoomName roomName) { + final String query = "INSERT INTO room(name, turn) VALUES(?, ?)"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, roomName.getValue()); + preparedStatement.setString(2, Color.WHITE.name()); + preparedStatement.executeUpdate(); + }); + } + + @Override + public void updateRoomTurn(Color color, Long roomId) { + final String query = "UPDATE room SET turn = ? WHERE id = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, color.name()); + preparedStatement.setLong(2, roomId); + preparedStatement.executeUpdate(); + }); + } + + @Override + public Room findRoomByName(RoomName roomName) { + List roomId = new ArrayList<>(); + final String query = "SELECT * FROM room WHERE name = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setString(1, roomName.getValue()); + ResultSet rs = preparedStatement.executeQuery(); + if (rs.next()) { + roomId.add(new Room(rs.getLong("id"), rs.getString("name"))); + } + }); + return roomId.get(0); + } + + @Override + public Color findTurnById(Long roomId) { + List color = new ArrayList<>(); + final String query = "SELECT turn FROM room WHERE id = ?"; + processQuery(query, preparedStatement -> { + preparedStatement.setLong(1, roomId); + ResultSet rs = preparedStatement.executeQuery(); + if (rs.next()) { + color.add(Color.valueOf(rs.getString("turn"))); + } + }); + return color.get(0); + } + + private void processQuery(String query, QueryProcessor queryProcessor) { + try (final Connection connection = dbConnection.getConnection()) { + final PreparedStatement preparedStatement = connection.prepareStatement(query); + queryProcessor.process(preparedStatement); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/chess/service/BoardService.java b/src/main/java/chess/service/BoardService.java new file mode 100644 index 00000000000..7d596367570 --- /dev/null +++ b/src/main/java/chess/service/BoardService.java @@ -0,0 +1,67 @@ +package chess.service; + +import chess.domain.board.position.Direction; +import chess.domain.board.position.Position; +import chess.domain.game.PositionsFilter; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.repository.BoardRepository; +import chess.repository.BoardRepositoryImpl; +import chess.repository.RoomRepository; +import chess.repository.RoomRepositoryImpl; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +public class BoardService { + + private final RoomRepository roomRepository = new RoomRepositoryImpl(); + private final BoardRepository boardRepository = new BoardRepositoryImpl(); + + public void movePiece(Position from, Position to, Long roomId) { + Piece piece = findFromPositionPiece(from, roomId); + Color currentTurn = findCurrentTurn(roomId, piece); + List movablePositions = generateMovablePositions(piece, from, roomId); + if (movablePositions.contains(to)) { + movePiece(from, to, piece, roomId); + roomRepository.updateRoomTurn(currentTurn.change(), roomId); + return; + } + throw new IllegalArgumentException("기물을 해당 위치로 이동시킬 수 없습니다."); + } + + private Piece findFromPositionPiece(Position from, Long roomId) { + if (!boardRepository.existsPieceByPosition(from, roomId)) { + throw new IllegalArgumentException("선택한 기물이 존재하지 않습니다."); + } + return boardRepository.findPieceByPosition(from, roomId); + } + + private Color findCurrentTurn(Long roomId, Piece piece) { + Color currentTurn = roomRepository.findTurnById(roomId); + if (piece.isNotSameColor(currentTurn)) { + throw new IllegalArgumentException("상대방의 기물을 움직일 수 없습니다. 현재 턴 : " + currentTurn); + } + return currentTurn; + } + + private List generateMovablePositions(Piece piece, Position position, Long roomId) { + Map> candidateAllPositions = piece.generateAllDirectionPositions(position); + return new PositionsFilter(boardRepository, candidateAllPositions).generateValidPositions(piece, roomId); + } + + private void movePiece(Position from, Position to, Piece piece, Long roomId) { + boardRepository.deletePieceByPosition(from, roomId); + boardRepository.deletePieceByPosition(to, roomId); + boardRepository.savePiece(piece, to, roomId); + } + + public boolean isCheckmate(Position position, Long roomId) { + return boardRepository.existsPieceByPosition(position, roomId) && boardRepository.findPieceByPosition(position, roomId) + .isKing(); + } + + public Map getAllPieces(Long roomId) { + return boardRepository.findAllPieceByRoomId(roomId); + } +} diff --git a/src/main/java/chess/service/GameService.java b/src/main/java/chess/service/GameService.java new file mode 100644 index 00000000000..a0da69905c6 --- /dev/null +++ b/src/main/java/chess/service/GameService.java @@ -0,0 +1,91 @@ +package chess.service; + +import chess.domain.board.BoardFactory; +import chess.domain.board.position.Position; +import chess.domain.game.Room; +import chess.domain.game.RoomName; +import chess.domain.game.Score; +import chess.domain.game.Winner; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.repository.BoardRepository; +import chess.repository.BoardRepositoryImpl; +import chess.repository.RoomRepository; +import chess.repository.RoomRepositoryImpl; +import chess.service.dto.ChessGameResult; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GameService { + + private static final int GAME_OVER_KING_COUNT = 1; + private static final int PWAN_DUPLICATE_THRESHOLD = 2; + private static final double PWAN_DEDUCTION_SCORE = 0.5; + + private final RoomRepository roomRepository = new RoomRepositoryImpl(); + private final BoardRepository boardRepository = new BoardRepositoryImpl(); + + public List findAllRoomNames() { + return roomRepository.findAllRoomNames(); + } + + public Room loadRoom(String input) { + RoomName roomName = new RoomName(input); + if (roomRepository.existsRoomName(roomName)) { + return roomRepository.findRoomByName(roomName); + } + return createRoom(roomName); + } + + private Room createRoom(RoomName roomName) { + roomRepository.saveRoom(roomName); + Room room = roomRepository.findRoomByName(roomName); + initializeBoard(room.getId()); + return room; + } + + private void initializeBoard(Long roomId) { + BoardFactory boardFactory = new BoardFactory(); + Map board = boardFactory.initialize(); + board.forEach((position, piece) -> boardRepository.savePiece(piece, position, roomId)); + } + + public ChessGameResult generateGameResult(Long roomId) { + Map teamScore = getScore(roomId); + List kings = boardRepository.findPieceByPieceType(PieceType.KING, roomId); + if (kings.size() == GAME_OVER_KING_COUNT) { + return new ChessGameResult(Winner.selectWinnerByCheckmate(kings.get(0).getColor()), teamScore); + } + return new ChessGameResult(Winner.selectWinnerByScore(teamScore), teamScore); + } + + public Map getScore(Long roomId) { + Map teamScore = new HashMap<>(); + teamScore.put(Color.WHITE, calculateTotalScore(Color.WHITE, PieceType.WHITE_PAWN, roomId)); + teamScore.put(Color.BLACK, calculateTotalScore(Color.BLACK, PieceType.BLACK_PAWN, roomId)); + return teamScore; + } + + private Score calculateTotalScore(Color color, PieceType pieceType, Long roomId) { + double sum = sumTotalScore(color, roomId); + double pawnMinus = calculatePawnScore(pieceType, roomId); + return new Score(sum - pawnMinus); + } + + private double sumTotalScore(Color color, Long roomId) { + List pieces = boardRepository.findPieceByColor(color, roomId); + return pieces.stream() + .mapToDouble(Piece::getScore) + .sum(); + } + + private double calculatePawnScore(PieceType pieceType, Long roomId) { + List pieceCount = boardRepository.getPieceCountByPieceType(pieceType, roomId); + return pieceCount.stream() + .filter(count -> count >= PWAN_DUPLICATE_THRESHOLD) + .mapToDouble(count -> count * PWAN_DEDUCTION_SCORE) + .sum(); + } +} diff --git a/src/main/java/chess/domain/game/ChessGameResult.java b/src/main/java/chess/service/dto/ChessGameResult.java similarity index 83% rename from src/main/java/chess/domain/game/ChessGameResult.java rename to src/main/java/chess/service/dto/ChessGameResult.java index 157661523e2..0d34d33031d 100644 --- a/src/main/java/chess/domain/game/ChessGameResult.java +++ b/src/main/java/chess/service/dto/ChessGameResult.java @@ -1,5 +1,7 @@ -package chess.domain.game; +package chess.service.dto; +import chess.domain.game.Score; +import chess.domain.game.Winner; import chess.domain.piece.Color; import java.util.Map; diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java index 6173e630268..aaa34304bd5 100644 --- a/src/main/java/chess/view/InputView.java +++ b/src/main/java/chess/view/InputView.java @@ -8,6 +8,10 @@ public class InputView { private static final Scanner scanner = new Scanner(System.in); + public static String readRoomName() { + return scanner.nextLine(); + } + public static List readCommend() { return Arrays.stream(scanner.nextLine().split(" ")).toList(); } diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index bf83addc618..3d524df2a88 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -1,12 +1,11 @@ package chess.view; -import chess.domain.board.Board; -import chess.domain.board.position.Row; -import chess.domain.game.ChessGameResult; +import chess.domain.board.position.Position; import chess.domain.game.Score; import chess.domain.game.Winner; import chess.domain.piece.Color; import chess.domain.piece.Piece; +import chess.service.dto.ChessGameResult; import chess.view.mapper.PieceMapper; import chess.view.mapper.RowMapper; import java.util.ArrayList; @@ -17,27 +16,42 @@ public class OutputView { private static final String EMPTY_BOARD = ". . . . . . . ."; - public static void printStartMessage() { - System.out.println("체스 게임을 시작합니다."); - System.out.println("게임 시작 : start"); + public static void printRoomNames(List roomNames) { + System.out.println("체스 게임을 시작합니다.\n"); + System.out.println("현재 저장된 체스 게임 방 목록입니다."); + + if (roomNames.size() == 0) { + System.out.println("-- 현재 존재하는 체스 게임 방이 없습니다. --"); + } + + for (String name : roomNames) { + System.out.println("- " + name); + } + + System.out.println("\n이어서 시작하려면 위에 보이는 방 이름을 입력해주세요."); + System.out.println("새로 시작하려면 새로운 방 이름을 입력해주세요."); + } + + public static void printStartMessage(String roomName) { + System.out.println(roomName + " 체스 방에 입장하였습니다."); + System.out.println("\n게임 시작 : start"); System.out.println("게임 종료 : end"); System.out.println("게임 이동 : move source위치 target위치 - 예. move b2 b3"); System.out.println("게임 점수 : status"); } - public static void printBoard(Board board) { + public static void printBoard(Map board) { List result = new ArrayList<>(); for (int i = 1; i <= 8; i++) { - result.add(new StringBuilder(EMPTY_BOARD + " | " + RowMapper.findByRow(Row.findByIndex(i)))); + result.add(new StringBuilder(EMPTY_BOARD + " | " + (9 - i))); } result.add(new StringBuilder("ㅡㅡㅡㅡㅡㅡㅡㅡㅡ")); result.add(new StringBuilder("a b c d e f g h")); - board.getBoard().keySet() + board.keySet() .forEach(position -> { - Piece piece = board.getBoard().get(position); -// int rowIndex = position.getRowIndex(); - int rowIndex = RowMapper.findByIndex(position.getRow()); + Piece piece = board.get(position); + int rowIndex = RowMapper.findIndexByRow(position.getRow()); int columnIndex = position.getColumnIndex(); result.get(rowIndex).replace(columnIndex * 2, columnIndex * 2 + 1, PieceMapper.findByPieceType(piece)); }); @@ -47,27 +61,42 @@ public static void printBoard(Board board) { } public static void printChessGameResult(ChessGameResult chessGameResult) { - StringBuilder stringBuilder = new StringBuilder("왕이 잡혀서 게임이 종료되었습니다. \n체스 게임 결과 : "); + System.out.print("왕이 죽어서 게임이 종료되었습니다. \n체스 게임 결과 : "); Winner winner = chessGameResult.getWinner(); Map teamScore = chessGameResult.getTeamScore(); + Score whiteScore = teamScore.get(Color.WHITE); + Score blackScore = teamScore.get(Color.BLACK); if (winner == Winner.WHITE_WIN) { - stringBuilder.append("흰색 승리!"); + System.out.println("흰색이 검은색 왕을 죽이고 승리하였습니다."); } if (winner == Winner.BLACK_WIN) { - stringBuilder.append("검정 승리!"); + System.out.println("검은색이 흰색 왕을 죽이고 승리하였습니다."); + } + printScore(whiteScore, blackScore); + } + + public static void printTeamScore(ChessGameResult chessGameResult) { + Winner winner = chessGameResult.getWinner(); + Map teamScore = chessGameResult.getTeamScore(); + Score whiteScore = teamScore.get(Color.WHITE); + Score blackScore = teamScore.get(Color.BLACK); + printScore(whiteScore, blackScore); + + if (winner == Winner.WHITE_WIN) { + System.out.println("현재 대국 상황은 흰색이 우세합니다."); + } + if (winner == Winner.BLACK_WIN) { + System.out.println("현재 대국 상황은 검은색이 우세합니다."); } if (winner == Winner.DRAW) { - stringBuilder.append("무승부!"); + System.out.println("현재 대국 상황이 호각입니다."); } - - System.out.println(stringBuilder); - printTeamScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); } - public static void printTeamScore(Score whiteTeamScore, Score blackTeamScore) { + private static void printScore(Score whiteScore, Score blackScore) { System.out.println("--- 기물 점수 ---"); - System.out.println("흰색: " + whiteTeamScore.score()); - System.out.println("검정: " + blackTeamScore.score()); + System.out.println("흰: " + whiteScore.score()); + System.out.println("검: " + blackScore.score()); } public static void printError(Exception exception) { diff --git a/src/main/java/chess/view/mapper/RowMapper.java b/src/main/java/chess/view/mapper/RowMapper.java index 22c1f867328..99b9a489360 100644 --- a/src/main/java/chess/view/mapper/RowMapper.java +++ b/src/main/java/chess/view/mapper/RowMapper.java @@ -4,14 +4,14 @@ import java.util.Arrays; public enum RowMapper { - RANK1(Row.ONE, "1", 7), - RANK2(Row.TWO, "2", 6), - RANK3(Row.THREE, "3", 5), - RANK4(Row.FOUR, "4", 4), - RANK5(Row.FIVE, "5", 3), - RANK6(Row.SIX, "6", 2), + RANK8(Row.EIGHT, "8", 0), RANK7(Row.SEVEN, "7", 1), - RANK8(Row.EIGHT, "8", 0); + RANK6(Row.SIX, "6", 2), + RANK5(Row.FIVE, "5", 3), + RANK4(Row.FOUR, "4", 4), + RANK3(Row.THREE, "3", 5), + RANK2(Row.TWO, "2", 6), + RANK1(Row.ONE, "1", 7); private final Row row; private final String value; @@ -31,15 +31,7 @@ public static Row findByInputValue(String value) { .row; } - public static String findByRow(Row row) { - return Arrays.stream(values()) - .filter(rowMapper -> rowMapper.row == row) - .findAny() - .orElseThrow(() -> new IllegalArgumentException("열과 일치하는 문자열이 존재하지 않습니다.")) - .value; - } - - public static int findByIndex(Row row) { + public static int findIndexByRow(Row row) { return Arrays.stream(values()) .filter(rowMapper -> rowMapper.row == row) .findAny() diff --git a/src/test/java/chess/controller/command/CommandRouterTest.java b/src/test/java/chess/controller/command/CommandRouterTest.java index ab80e16f58e..f049f97cd98 100644 --- a/src/test/java/chess/controller/command/CommandRouterTest.java +++ b/src/test/java/chess/controller/command/CommandRouterTest.java @@ -54,6 +54,6 @@ void commendInputFormatSizeTest() { void findCommendByInputFailTest() { assertThatThrownBy(() -> CommandRouter.findCommendByInput(List.of("jazz"))) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("옳바르지 않은 명령어 입력입니다."); + .hasMessage("올바르지 않은 명령어 입력입니다."); } } diff --git a/src/test/java/chess/controller/command/EndTest.java b/src/test/java/chess/controller/command/EndTest.java index 9d4ac6c80b1..db4db13ac0e 100644 --- a/src/test/java/chess/controller/command/EndTest.java +++ b/src/test/java/chess/controller/command/EndTest.java @@ -5,7 +5,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import chess.controller.State; -import chess.domain.game.ChessGame; +import chess.service.BoardService; +import chess.service.GameService; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,9 +32,10 @@ void validateCommandInputSizeFailTest() { @Test void executeTest() { End end = new End(List.of("end")); - ChessGame chessGame = new ChessGame(); + GameService gameService = new GameService(); + BoardService boardService = new BoardService(); - State gameState = end.execute(chessGame); + State gameState = end.execute(gameService, boardService, 0L); assertThat(gameState).isEqualTo(State.END); } diff --git a/src/test/java/chess/controller/command/MoveTest.java b/src/test/java/chess/controller/command/MoveTest.java index a37a532acf6..33d5db595d5 100644 --- a/src/test/java/chess/controller/command/MoveTest.java +++ b/src/test/java/chess/controller/command/MoveTest.java @@ -1,11 +1,8 @@ package chess.controller.command; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import chess.controller.State; -import chess.domain.game.ChessGame; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -26,15 +23,15 @@ void validateCommandInputSizeFailTest() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("게임 이동 명령어 입력 형식이 올바르지 않습니다."); } - - @DisplayName("기능을 수행한 후 RUNNING 상태를 반환한다.") - @Test - void executeTest() { - Move move = new Move(List.of("move", "b2", "b4")); - ChessGame chessGame = new ChessGame(); - - State gameState = move.execute(chessGame); - - assertThat(gameState).isEqualTo(State.RUNNING); - } +// +// @DisplayName("기능을 수행한 후 RUNNING 상태를 반환한다.") +// @Test +// void executeTest() { +// Move move = new Move(List.of("move", "b2", "b4")); +// GameService gameService = new GameService(); +// BoardService boardService = new BoardService(); +// State gameState = move.execute(gameService, boardService, 0L); +// +// assertThat(gameState).isEqualTo(State.RUNNING); +// } } diff --git a/src/test/java/chess/controller/command/StartTest.java b/src/test/java/chess/controller/command/StartTest.java index 60a952b565e..bc64900f654 100644 --- a/src/test/java/chess/controller/command/StartTest.java +++ b/src/test/java/chess/controller/command/StartTest.java @@ -5,7 +5,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import chess.controller.State; -import chess.domain.game.ChessGame; +import chess.service.BoardService; +import chess.service.GameService; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,9 +32,9 @@ void validateCommandInputSizeFailTest() { @Test void executeTest() { Start start = new Start(List.of("start")); - ChessGame chessGame = new ChessGame(); - - State gameState = start.execute(chessGame); + GameService gameService = new GameService(); + BoardService boardService = new BoardService(); + State gameState = start.execute(gameService, boardService, 0L); assertThat(gameState).isEqualTo(State.RUNNING); } diff --git a/src/test/java/chess/controller/command/StatusTest.java b/src/test/java/chess/controller/command/StatusTest.java index 1e9d7840425..d2d8f76d912 100644 --- a/src/test/java/chess/controller/command/StatusTest.java +++ b/src/test/java/chess/controller/command/StatusTest.java @@ -5,7 +5,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import chess.controller.State; -import chess.domain.game.ChessGame; +import chess.service.BoardService; +import chess.service.GameService; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,9 +32,9 @@ void validateCommandInputSizeFailTest() { @Test void executeTest() { Status status = new Status(List.of("status")); - ChessGame chessGame = new ChessGame(); - - State gameState = status.execute(chessGame); + GameService gameService = new GameService(); + BoardService boardService = new BoardService(); + State gameState = status.execute(gameService, boardService, 0L); assertThat(gameState).isEqualTo(State.RUNNING); } diff --git a/src/test/java/chess/domain/board/BoardTest.java b/src/test/java/chess/domain/board/BoardTest.java deleted file mode 100644 index 16571ae1c2d..00000000000 --- a/src/test/java/chess/domain/board/BoardTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package chess.domain.board; - -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import chess.domain.board.position.Column; -import chess.domain.board.position.Position; -import chess.domain.board.position.Row; -import chess.domain.game.Score; -import chess.domain.piece.Color; -import chess.domain.piece.Piece; -import chess.domain.piece.PieceType; -import java.util.HashMap; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -class BoardTest { - - @Nested - @DisplayName("기물 점수 계산 테스트") - class CalculateScoreTest { - - @Test - void calculateTeamScoreTest() { - Map map = new HashMap<>(); - - map.put(new Position(Row.ONE, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.TWO, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.THREE, Column.B), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); - map.put(new Position(Row.ONE, Column.D), new Piece(PieceType.QUEEN, Color.WHITE)); - map.put(new Position(Row.ONE, Column.E), new Piece(PieceType.KING, Color.WHITE)); - map.put(new Position(Row.TWO, Column.F), new Piece(PieceType.ROOK, Color.WHITE)); - - map.put(new Position(Row.EIGHT, Column.G), new Piece(PieceType.KNIGHT, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.F), new Piece(PieceType.BISHOP, Color.BLACK)); - map.put(new Position(Row.EIGHT, Column.E), new Piece(PieceType.KING, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.F), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.D), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - map.put(new Position(Row.SEVEN, Column.E), new Piece(PieceType.BLACK_PAWN, Color.BLACK)); - - Board board = new Board(map); - Map scoreOfTeam = board.calculateScore(); - - assertAll( - () -> assertEquals(scoreOfTeam.get(Color.WHITE), new Score(15.5)), - () -> assertEquals(scoreOfTeam.get(Color.BLACK), new Score(8.5)) - ); - } - } -} diff --git a/src/test/java/chess/domain/board/RowTest.java b/src/test/java/chess/domain/board/RowTest.java index d2d1a5abefb..611e41918f1 100644 --- a/src/test/java/chess/domain/board/RowTest.java +++ b/src/test/java/chess/domain/board/RowTest.java @@ -17,9 +17,9 @@ void calculateNextRowSuccessTest() { Row row = Row.FOUR; assertAll( - () -> assertEquals(Row.FIVE, row.calculateNextRow(1)), - () -> assertEquals(Row.THREE, row.calculateNextRow(-1)), - () -> assertEquals(Row.FOUR, row.calculateNextRow(0)) + () -> assertEquals(Row.FIVE, row.calculateNextRow(1)), + () -> assertEquals(Row.THREE, row.calculateNextRow(-1)), + () -> assertEquals(Row.FOUR, row.calculateNextRow(0)) ); } @@ -29,15 +29,39 @@ void calculateNextRowFailTest() { Row row = Row.FOUR; assertThatThrownBy(() -> row.calculateNextRow(-5)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("다음 위치로 이동할 수 있는 열이 없습니다."); } @Test @DisplayName("거리 만큼 이동한 값이 보드판을 벗어난 경우 false를 반환한다.") void isNextInRange() { assertAll( - () -> assertFalse(Row.EIGHT.isNextInRange(1)), - () -> assertFalse(Row.ONE.isNextInRange(-1)) + () -> assertFalse(Row.EIGHT.isNextInRange(1)), + () -> assertFalse(Row.ONE.isNextInRange(-1)) ); } + + @Test + @DisplayName("인덱스로 일치하는 열을 반환한다.") + void findByIndexTest() { + assertAll( + () -> assertEquals(Row.EIGHT, Row.findByIndex(8)), + () -> assertEquals(Row.SEVEN, Row.findByIndex(7)), + () -> assertEquals(Row.SIX, Row.findByIndex(6)), + () -> assertEquals(Row.FIVE, Row.findByIndex(5)), + () -> assertEquals(Row.FOUR, Row.findByIndex(4)), + () -> assertEquals(Row.THREE, Row.findByIndex(3)), + () -> assertEquals(Row.TWO, Row.findByIndex(2)), + () -> assertEquals(Row.ONE, Row.findByIndex(1)) + ); + } + + @Test + @DisplayName("인덱스로 일치하는 열 반환에 실패하면 에러를 반환한다.") + void findByIndexFailTest() { + assertThatThrownBy(() -> Row.findByIndex(-1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("열과 일치하는 인덱스가 없습니다."); + } } diff --git a/src/test/java/chess/domain/game/WinnerTest.java b/src/test/java/chess/domain/game/WinnerTest.java index fd439dc01ca..e290c7f0db6 100644 --- a/src/test/java/chess/domain/game/WinnerTest.java +++ b/src/test/java/chess/domain/game/WinnerTest.java @@ -49,18 +49,18 @@ void blackTeamScoreEqualWhiteTeam() { @DisplayName("체크메이트로 승리를 결정한다") class SelectWinnerByCheckmateTest { - @DisplayName("검정 색의 King이 체크메이트를 당하면 흰색 팀이 승리한다.") + @DisplayName("혼자 살아있는 왕이 흰색이면 흰색이 승리한다.") @Test void blackKingCheckmateTest() { - Winner winner = Winner.selectWinnerByCheckmate(Color.BLACK); + Winner winner = Winner.selectWinnerByCheckmate(Color.WHITE); assertThat(winner).isEqualTo(Winner.WHITE_WIN); } - @DisplayName("흰색 색의 King이 체크메이트를 당하면 검정 팀이 승리한다.") + @DisplayName("혼자 살아있는 왕이 검은색이면 검은색이 승리한다.") @Test void whiteKingCheckmateTest() { - Winner winner = Winner.selectWinnerByCheckmate(Color.WHITE); + Winner winner = Winner.selectWinnerByCheckmate(Color.BLACK); assertThat(winner).isEqualTo(Winner.BLACK_WIN); } diff --git a/src/test/java/chess/domain/mock/BlackPieceRepository.java b/src/test/java/chess/domain/mock/BlackPieceRepository.java index 16333b38c3f..ec65acb3b8f 100644 --- a/src/test/java/chess/domain/mock/BlackPieceRepository.java +++ b/src/test/java/chess/domain/mock/BlackPieceRepository.java @@ -11,40 +11,40 @@ public class BlackPieceRepository implements BoardRepository { @Override - public void savePiece(Piece piece, Position position) { + public void savePiece(Piece piece, Position position, Long roomId) { } @Override - public boolean existsPieceByPosition(Position position) { + public boolean existsPieceByPosition(Position position, Long roomId) { return true; } @Override - public void deletePieceByPosition(Position position) { + public void deletePieceByPosition(Position position, Long roomId) { } @Override - public Piece findPieceByPosition(Position position) { + public Piece findPieceByPosition(Position position, Long roomId) { return new Piece(PieceType.BLACK_PAWN, Color.BLACK); } @Override - public List findPieceByColor(Color color) { + public List findPieceByColor(Color piece_color, Long roomId) { return null; } @Override - public List getPieceCountByPieceType(PieceType pieceType) { + public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { return null; } @Override - public Map findAllPiece() { + public Map findAllPieceByRoomId(Long roomId) { return null; } @Override - public List findPieceByPieceType(PieceType pieceType) { + public List findPieceByPieceType(PieceType pieceType, Long roomId) { return null; } } diff --git a/src/test/java/chess/domain/mock/NotExistsPieceRepository.java b/src/test/java/chess/domain/mock/NotExistsPieceRepository.java index b815827a851..b8a40d523f1 100644 --- a/src/test/java/chess/domain/mock/NotExistsPieceRepository.java +++ b/src/test/java/chess/domain/mock/NotExistsPieceRepository.java @@ -11,38 +11,40 @@ public class NotExistsPieceRepository implements BoardRepository { @Override - public void savePiece(Piece piece, Position position) {} + public void savePiece(Piece piece, Position position, Long roomId) { + } @Override - public boolean existsPieceByPosition(Position position) { + public boolean existsPieceByPosition(Position position, Long roomId) { return false; } @Override - public void deletePieceByPosition(Position position) {} + public void deletePieceByPosition(Position position, Long roomId) { + } @Override - public Piece findPieceByPosition(Position position) { + public Piece findPieceByPosition(Position position, Long roomId) { return null; } @Override - public List findPieceByColor(Color color) { + public List findPieceByColor(Color piece_color, Long roomId) { return null; } @Override - public List getPieceCountByPieceType(PieceType pieceType) { + public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { return null; } @Override - public Map findAllPiece() { + public Map findAllPieceByRoomId(Long roomId) { return null; } @Override - public List findPieceByPieceType(PieceType pieceType) { + public List findPieceByPieceType(PieceType pieceType, Long roomId) { return null; } } diff --git a/src/test/java/chess/domain/mock/WhitePieceRepository.java b/src/test/java/chess/domain/mock/WhitePieceRepository.java index 58c9548ee00..193a4b70b4a 100644 --- a/src/test/java/chess/domain/mock/WhitePieceRepository.java +++ b/src/test/java/chess/domain/mock/WhitePieceRepository.java @@ -11,38 +11,40 @@ public class WhitePieceRepository implements BoardRepository { @Override - public void savePiece(Piece piece, Position position) {} + public void savePiece(Piece piece, Position position, Long roomId) { + } @Override - public boolean existsPieceByPosition(Position position) { + public boolean existsPieceByPosition(Position position, Long roomId) { return true; } @Override - public void deletePieceByPosition(Position position) {} + public void deletePieceByPosition(Position position, Long roomId) { + } @Override - public Piece findPieceByPosition(Position position) { + public Piece findPieceByPosition(Position position, Long roomId) { return new Piece(PieceType.WHITE_PAWN, Color.WHITE); } @Override - public List findPieceByColor(Color color) { + public List findPieceByColor(Color piece_color, Long roomId) { return null; } @Override - public List getPieceCountByPieceType(PieceType pieceType) { + public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { return null; } @Override - public Map findAllPiece() { + public Map findAllPieceByRoomId(Long roomId) { return null; } @Override - public List findPieceByPieceType(PieceType pieceType) { + public List findPieceByPieceType(PieceType pieceType, Long roomId) { return null; } } diff --git a/src/test/java/chess/domain/positionFilter/KingTest.java b/src/test/java/chess/domain/positionFilter/KingTest.java index 6a35fbcb1fc..63c525e35fb 100644 --- a/src/test/java/chess/domain/positionFilter/KingTest.java +++ b/src/test/java/chess/domain/positionFilter/KingTest.java @@ -23,14 +23,14 @@ class KingTest { @Test @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") - void startPositionPawnWithOnlyAttackPossiblePositions() { + void positionEmptyAllMovablePositionsIncludedTest() { Piece piece = new Piece(PieceType.KING, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.D), @@ -46,14 +46,14 @@ void startPositionPawnWithOnlyAttackPossiblePositions() { @Test @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") - void startPositionPawnWithFreePositions() { + void positionWithOpponentPiecesTest() { Piece piece = new Piece(PieceType.KING, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.D), @@ -69,14 +69,14 @@ void startPositionPawnWithFreePositions() { @Test @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") - void startPositionPawnWithCantMovePositions() { + void positionWithOwnPiecesTest() { Piece piece = new Piece(PieceType.KING, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).isEmpty(); } diff --git a/src/test/java/chess/domain/positionFilter/KnightTest.java b/src/test/java/chess/domain/positionFilter/KnightTest.java index a1f27d1bff6..863d42f1c77 100644 --- a/src/test/java/chess/domain/positionFilter/KnightTest.java +++ b/src/test/java/chess/domain/positionFilter/KnightTest.java @@ -23,14 +23,14 @@ class KnightTest { @Test @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") - void startPositionPawnWithOnlyAttackPossiblePositions() { + void positionEmptyAllMovablePositionsIncludedTest() { Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SEVEN, Column.C), @@ -46,14 +46,14 @@ void startPositionPawnWithOnlyAttackPossiblePositions() { @Test @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") - void startPositionPawnWithFreePositions() { + void positionWithOpponentPiecesTest() { Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SEVEN, Column.C), @@ -69,14 +69,14 @@ void startPositionPawnWithFreePositions() { @Test @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") - void startPositionPawnWithCantMovePositions() { + void positionWithOwnPiecesTest() { Piece piece = new Piece(PieceType.KNIGHT, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).isEmpty(); } diff --git a/src/test/java/chess/domain/positionFilter/PawnTest.java b/src/test/java/chess/domain/positionFilter/PawnTest.java index 06af5f4b86d..0647e5444ff 100644 --- a/src/test/java/chess/domain/positionFilter/PawnTest.java +++ b/src/test/java/chess/domain/positionFilter/PawnTest.java @@ -23,14 +23,14 @@ class PawnTest { @Test @DisplayName("시작 위치 앞 2칸이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") - void startPositionPawnWithOnlyAttackPossiblePositions() { + void startWithEmptyFrontTwoPositionsTest() { Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); Position position = new Position(Row.TWO, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.THREE, Column.D), @@ -40,14 +40,14 @@ void startPositionPawnWithOnlyAttackPossiblePositions() { @Test @DisplayName("대각선에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") - void startPositionPawnWithFreePositions() { + void diagonalMoveWithOpponentPiecePresentTest() { Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); Position position = new Position(Row.TWO, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.THREE, Column.C), @@ -57,14 +57,14 @@ void startPositionPawnWithFreePositions() { @Test @DisplayName("앞에 기물이 존재하고 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") - void startPositionPawnWithCantMovePositions() { + void cannotMoveIfFriendlyPieceAhead() { Piece piece = new Piece(PieceType.WHITE_PAWN, Color.WHITE); Position position = new Position(Row.TWO, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).isEmpty(); } diff --git a/src/test/java/chess/domain/positionFilter/QueenTest.java b/src/test/java/chess/domain/positionFilter/QueenTest.java index cd45fbde0eb..404726d7e78 100644 --- a/src/test/java/chess/domain/positionFilter/QueenTest.java +++ b/src/test/java/chess/domain/positionFilter/QueenTest.java @@ -23,14 +23,14 @@ class QueenTest { @Test @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") - void startPositionPawnWithOnlyAttackPossiblePositions() { + void positionEmptyAllMovablePositionsIncludedTest() { Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.E), @@ -72,14 +72,14 @@ void startPositionPawnWithOnlyAttackPossiblePositions() { @Test @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") - void startPositionPawnWithFreePositions() { + void positionWithOpponentPiecesTest() { Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.E), @@ -95,14 +95,14 @@ void startPositionPawnWithFreePositions() { @Test @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") - void startPositionPawnWithCantMovePositions() { + void positionWithOwnPiecesTest() { Piece piece = new Piece(PieceType.QUEEN, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).isEmpty(); } diff --git a/src/test/java/chess/domain/positionFilter/RookTest.java b/src/test/java/chess/domain/positionFilter/RookTest.java index 0e7fec0fd34..b82fe30f688 100644 --- a/src/test/java/chess/domain/positionFilter/RookTest.java +++ b/src/test/java/chess/domain/positionFilter/RookTest.java @@ -23,14 +23,14 @@ class RookTest { @Test @DisplayName("해당 포지션이 비어있을 시 이동 가능한 포지션에 모두 포함되어야 한다.") - void startPositionPawnWithOnlyAttackPossiblePositions() { + void positionEmptyAllMovablePositionsIncludedTest() { Piece piece = new Piece(PieceType.ROOK, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new NotExistsPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.D), @@ -55,14 +55,14 @@ void startPositionPawnWithOnlyAttackPossiblePositions() { @Test @DisplayName("해당 포지션에 상대 기물이 존재하면 이동할 수 있는 위치에 포함되어야 한다.") - void startPositionPawnWithFreePositions() { + void positionWithOpponentPiecesTest() { Piece piece = new Piece(PieceType.ROOK, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new BlackPieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).containsExactlyInAnyOrder( new Position(Row.SIX, Column.D), @@ -74,14 +74,14 @@ void startPositionPawnWithFreePositions() { @Test @DisplayName("해당 포지션이 우리팀 기물일 시 이동가능한 위치에 포함되어서는 안된다.") - void startPositionPawnWithCantMovePositions() { + void positionWithOwnPiecesTest() { Piece piece = new Piece(PieceType.ROOK, Color.WHITE); Position position = new Position(Row.FIVE, Column.D); Map> candidateAllPositions = piece.generateAllDirectionPositions(position); PositionsFilter positionsFilter = new PositionsFilter(new WhitePieceRepository(), candidateAllPositions); - List movablePositions = positionsFilter.generateValidPositions(piece); + List movablePositions = positionsFilter.generateValidPositions(piece, 0L); assertThat(movablePositions).isEmpty(); } diff --git a/src/test/java/chess/view/mapper/RowMapperTest.java b/src/test/java/chess/view/mapper/RowMapperTest.java index dca694cd741..7ea5314d669 100644 --- a/src/test/java/chess/view/mapper/RowMapperTest.java +++ b/src/test/java/chess/view/mapper/RowMapperTest.java @@ -34,19 +34,4 @@ void findByInputValueFailTest(String value) { assertThatThrownBy(() -> RowMapper.findByInputValue(value)) .isInstanceOf(IllegalArgumentException.class); } - - @Test - @DisplayName("Row로 문자열을 찾는다.") - void findByRowSuccessTest() { - assertAll( - () -> assertEquals("1", RowMapper.findByRow(Row.ONE)), - () -> assertEquals("2", RowMapper.findByRow(Row.TWO)), - () -> assertEquals("3", RowMapper.findByRow(Row.THREE)), - () -> assertEquals("4", RowMapper.findByRow(Row.FOUR)), - () -> assertEquals("5", RowMapper.findByRow(Row.FIVE)), - () -> assertEquals("6", RowMapper.findByRow(Row.SIX)), - () -> assertEquals("7", RowMapper.findByRow(Row.SEVEN)), - () -> assertEquals("8", RowMapper.findByRow(Row.EIGHT)) - ); - } } From 50627660cbd64462bd702bb86373afc227486a8c Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 22:43:31 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=20repository=EB=A5=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9E=90=EB=A1=9C=20=EC=A3=BC=EC=9E=85?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Application.java | 11 +++++++++-- src/main/java/chess/service/BoardService.java | 11 +++++++---- src/main/java/chess/service/GameService.java | 11 +++++++---- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java index 40fd9939255..547cde9e180 100644 --- a/src/main/java/chess/Application.java +++ b/src/main/java/chess/Application.java @@ -1,13 +1,20 @@ package chess; import chess.controller.ChessGameController; +import chess.repository.BoardRepository; +import chess.repository.BoardRepositoryImpl; +import chess.repository.RoomRepository; +import chess.repository.RoomRepositoryImpl; import chess.service.BoardService; import chess.service.GameService; public class Application { public static void main(String[] args) { - GameService gameService = new GameService(); - BoardService boardService = new BoardService(); + RoomRepository roomRepository = new RoomRepositoryImpl(); + BoardRepository boardRepository = new BoardRepositoryImpl(); + + GameService gameService = new GameService(roomRepository, boardRepository); + BoardService boardService = new BoardService(roomRepository, boardRepository); ChessGameController chessGameController = new ChessGameController(gameService, boardService); chessGameController.run(); } diff --git a/src/main/java/chess/service/BoardService.java b/src/main/java/chess/service/BoardService.java index 7d596367570..87a9a332590 100644 --- a/src/main/java/chess/service/BoardService.java +++ b/src/main/java/chess/service/BoardService.java @@ -6,17 +6,20 @@ import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.repository.BoardRepository; -import chess.repository.BoardRepositoryImpl; import chess.repository.RoomRepository; -import chess.repository.RoomRepositoryImpl; import java.util.List; import java.util.Map; import java.util.Queue; public class BoardService { - private final RoomRepository roomRepository = new RoomRepositoryImpl(); - private final BoardRepository boardRepository = new BoardRepositoryImpl(); + private final RoomRepository roomRepository; + private final BoardRepository boardRepository; + + public BoardService(RoomRepository roomRepository, BoardRepository boardRepository) { + this.roomRepository = roomRepository; + this.boardRepository = boardRepository; + } public void movePiece(Position from, Position to, Long roomId) { Piece piece = findFromPositionPiece(from, roomId); diff --git a/src/main/java/chess/service/GameService.java b/src/main/java/chess/service/GameService.java index a0da69905c6..471277adbf9 100644 --- a/src/main/java/chess/service/GameService.java +++ b/src/main/java/chess/service/GameService.java @@ -10,9 +10,7 @@ import chess.domain.piece.Piece; import chess.domain.piece.PieceType; import chess.repository.BoardRepository; -import chess.repository.BoardRepositoryImpl; import chess.repository.RoomRepository; -import chess.repository.RoomRepositoryImpl; import chess.service.dto.ChessGameResult; import java.util.HashMap; import java.util.List; @@ -24,8 +22,13 @@ public class GameService { private static final int PWAN_DUPLICATE_THRESHOLD = 2; private static final double PWAN_DEDUCTION_SCORE = 0.5; - private final RoomRepository roomRepository = new RoomRepositoryImpl(); - private final BoardRepository boardRepository = new BoardRepositoryImpl(); + private final RoomRepository roomRepository; + private final BoardRepository boardRepository; + + public GameService(RoomRepository roomRepository, BoardRepository boardRepository) { + this.roomRepository = roomRepository; + this.boardRepository = boardRepository; + } public List findAllRoomNames() { return roomRepository.findAllRoomNames(); From 0777b71ad18d4c16f121fee9ed4edd42187b5910 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 22:43:54 +0900 Subject: [PATCH 12/18] =?UTF-8?q?refactor:=20fake=20repository=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=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/test/java/chess/domain/positionFilter/BishopTest.java | 6 +++--- src/test/java/chess/domain/positionFilter/KingTest.java | 6 +++--- src/test/java/chess/domain/positionFilter/KnightTest.java | 6 +++--- src/test/java/chess/domain/positionFilter/PawnTest.java | 6 +++--- src/test/java/chess/domain/positionFilter/QueenTest.java | 6 +++--- src/test/java/chess/domain/positionFilter/RookTest.java | 6 +++--- .../mock => repository/fake}/BlackPieceRepository.java | 2 +- .../mock => repository/fake}/NotExistsPieceRepository.java | 2 +- .../mock => repository/fake}/WhitePieceRepository.java | 2 +- 9 files changed, 21 insertions(+), 21 deletions(-) rename src/test/java/chess/{domain/mock => repository/fake}/BlackPieceRepository.java (97%) rename src/test/java/chess/{domain/mock => repository/fake}/NotExistsPieceRepository.java (97%) rename src/test/java/chess/{domain/mock => repository/fake}/WhitePieceRepository.java (97%) diff --git a/src/test/java/chess/domain/positionFilter/BishopTest.java b/src/test/java/chess/domain/positionFilter/BishopTest.java index 2e67c0ef71d..39585e641a1 100644 --- a/src/test/java/chess/domain/positionFilter/BishopTest.java +++ b/src/test/java/chess/domain/positionFilter/BishopTest.java @@ -7,12 +7,12 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; -import chess.domain.mock.BlackPieceRepository; -import chess.domain.mock.NotExistsPieceRepository; -import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import chess.repository.fake.BlackPieceRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; import java.util.List; import java.util.Map; import java.util.Queue; diff --git a/src/test/java/chess/domain/positionFilter/KingTest.java b/src/test/java/chess/domain/positionFilter/KingTest.java index 63c525e35fb..d0ae5345679 100644 --- a/src/test/java/chess/domain/positionFilter/KingTest.java +++ b/src/test/java/chess/domain/positionFilter/KingTest.java @@ -7,12 +7,12 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; -import chess.domain.mock.BlackPieceRepository; -import chess.domain.mock.NotExistsPieceRepository; -import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import chess.repository.fake.BlackPieceRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; import java.util.List; import java.util.Map; import java.util.Queue; diff --git a/src/test/java/chess/domain/positionFilter/KnightTest.java b/src/test/java/chess/domain/positionFilter/KnightTest.java index 863d42f1c77..3cfe78c11f3 100644 --- a/src/test/java/chess/domain/positionFilter/KnightTest.java +++ b/src/test/java/chess/domain/positionFilter/KnightTest.java @@ -7,12 +7,12 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; -import chess.domain.mock.BlackPieceRepository; -import chess.domain.mock.NotExistsPieceRepository; -import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import chess.repository.fake.BlackPieceRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; import java.util.List; import java.util.Map; import java.util.Queue; diff --git a/src/test/java/chess/domain/positionFilter/PawnTest.java b/src/test/java/chess/domain/positionFilter/PawnTest.java index 0647e5444ff..f7319731b5d 100644 --- a/src/test/java/chess/domain/positionFilter/PawnTest.java +++ b/src/test/java/chess/domain/positionFilter/PawnTest.java @@ -7,12 +7,12 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; -import chess.domain.mock.BlackPieceRepository; -import chess.domain.mock.NotExistsPieceRepository; -import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import chess.repository.fake.BlackPieceRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; import java.util.List; import java.util.Map; import java.util.Queue; diff --git a/src/test/java/chess/domain/positionFilter/QueenTest.java b/src/test/java/chess/domain/positionFilter/QueenTest.java index 404726d7e78..f659530cc07 100644 --- a/src/test/java/chess/domain/positionFilter/QueenTest.java +++ b/src/test/java/chess/domain/positionFilter/QueenTest.java @@ -7,12 +7,12 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; -import chess.domain.mock.BlackPieceRepository; -import chess.domain.mock.NotExistsPieceRepository; -import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import chess.repository.fake.BlackPieceRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; import java.util.List; import java.util.Map; import java.util.Queue; diff --git a/src/test/java/chess/domain/positionFilter/RookTest.java b/src/test/java/chess/domain/positionFilter/RookTest.java index b82fe30f688..b366ded744d 100644 --- a/src/test/java/chess/domain/positionFilter/RookTest.java +++ b/src/test/java/chess/domain/positionFilter/RookTest.java @@ -7,12 +7,12 @@ import chess.domain.board.position.Position; import chess.domain.board.position.Row; import chess.domain.game.PositionsFilter; -import chess.domain.mock.BlackPieceRepository; -import chess.domain.mock.NotExistsPieceRepository; -import chess.domain.mock.WhitePieceRepository; import chess.domain.piece.Color; import chess.domain.piece.Piece; import chess.domain.piece.PieceType; +import chess.repository.fake.BlackPieceRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; import java.util.List; import java.util.Map; import java.util.Queue; diff --git a/src/test/java/chess/domain/mock/BlackPieceRepository.java b/src/test/java/chess/repository/fake/BlackPieceRepository.java similarity index 97% rename from src/test/java/chess/domain/mock/BlackPieceRepository.java rename to src/test/java/chess/repository/fake/BlackPieceRepository.java index ec65acb3b8f..933843e6b68 100644 --- a/src/test/java/chess/domain/mock/BlackPieceRepository.java +++ b/src/test/java/chess/repository/fake/BlackPieceRepository.java @@ -1,4 +1,4 @@ -package chess.domain.mock; +package chess.repository.fake; import chess.domain.board.position.Position; import chess.domain.piece.Color; diff --git a/src/test/java/chess/domain/mock/NotExistsPieceRepository.java b/src/test/java/chess/repository/fake/NotExistsPieceRepository.java similarity index 97% rename from src/test/java/chess/domain/mock/NotExistsPieceRepository.java rename to src/test/java/chess/repository/fake/NotExistsPieceRepository.java index b8a40d523f1..63b2ca9fa5a 100644 --- a/src/test/java/chess/domain/mock/NotExistsPieceRepository.java +++ b/src/test/java/chess/repository/fake/NotExistsPieceRepository.java @@ -1,4 +1,4 @@ -package chess.domain.mock; +package chess.repository.fake; import chess.domain.board.position.Position; import chess.domain.piece.Color; diff --git a/src/test/java/chess/domain/mock/WhitePieceRepository.java b/src/test/java/chess/repository/fake/WhitePieceRepository.java similarity index 97% rename from src/test/java/chess/domain/mock/WhitePieceRepository.java rename to src/test/java/chess/repository/fake/WhitePieceRepository.java index 193a4b70b4a..3c8ce2b6627 100644 --- a/src/test/java/chess/domain/mock/WhitePieceRepository.java +++ b/src/test/java/chess/repository/fake/WhitePieceRepository.java @@ -1,4 +1,4 @@ -package chess.domain.mock; +package chess.repository.fake; import chess.domain.board.position.Position; import chess.domain.piece.Color; From b4ce5773fb31347e5f0ab42c7b5cee6cb49df832 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 23:39:32 +0900 Subject: [PATCH 13/18] =?UTF-8?q?feat:=20fake=20repository=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 --- .../repository/fake/FakeBoardRepository.java | 62 +++++++++++++++++++ .../repository/fake/FakeRoomRepository.java | 39 ++++++++++++ .../repository/fake/WhitePieceRepository.java | 11 +++- 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 src/test/java/chess/repository/fake/FakeBoardRepository.java create mode 100644 src/test/java/chess/repository/fake/FakeRoomRepository.java diff --git a/src/test/java/chess/repository/fake/FakeBoardRepository.java b/src/test/java/chess/repository/fake/FakeBoardRepository.java new file mode 100644 index 00000000000..e56de498c6d --- /dev/null +++ b/src/test/java/chess/repository/fake/FakeBoardRepository.java @@ -0,0 +1,62 @@ +package chess.repository.fake; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.domain.piece.Color; +import chess.domain.piece.Piece; +import chess.domain.piece.PieceType; +import chess.repository.BoardRepository; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FakeBoardRepository implements BoardRepository { + + @Override + public void savePiece(Piece piece, Position position, Long roomId) { + } + + @Override + public boolean existsPieceByPosition(Position position, Long roomId) { + return true; + } + + @Override + public void deletePieceByPosition(Position position, Long roomId) { + } + + @Override + public Piece findPieceByPosition(Position position, Long roomId) { + return new Piece(PieceType.KING, Color.WHITE); + } + + @Override + public List findPieceByColor(Color piece_color, Long roomId) { + return List.of( + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.ROOK, Color.WHITE)); + } + + @Override + public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { + return List.of(2, 2); + } + + @Override + public Map findAllPieceByRoomId(Long roomId) { + Map map = new HashMap<>(); + map.put(new Position(Row.TWO, Column.C), new Piece(PieceType.WHITE_PAWN, Color.WHITE)); + return map; + } + + @Override + public List findPieceByPieceType(PieceType pieceType, Long roomId) { + return List.of( + new Piece(PieceType.KING, Color.WHITE), + new Piece(PieceType.KING, Color.BLACK)); + } +} diff --git a/src/test/java/chess/repository/fake/FakeRoomRepository.java b/src/test/java/chess/repository/fake/FakeRoomRepository.java new file mode 100644 index 00000000000..4d7aa89e3b1 --- /dev/null +++ b/src/test/java/chess/repository/fake/FakeRoomRepository.java @@ -0,0 +1,39 @@ +package chess.repository.fake; + +import chess.domain.game.Room; +import chess.domain.game.RoomName; +import chess.domain.piece.Color; +import chess.repository.RoomRepository; +import java.util.List; + +public class FakeRoomRepository implements RoomRepository { + @Override + public List findAllRoomNames() { + return null; + } + + @Override + public boolean existsRoomName(RoomName roomName) { + return false; + } + + @Override + public void saveRoom(RoomName roomName) { + + } + + @Override + public void updateRoomTurn(Color color, Long roomId) { + + } + + @Override + public Room findRoomByName(RoomName roomName) { + return null; + } + + @Override + public Color findTurnById(Long roomId) { + return Color.BLACK; + } +} diff --git a/src/test/java/chess/repository/fake/WhitePieceRepository.java b/src/test/java/chess/repository/fake/WhitePieceRepository.java index 3c8ce2b6627..38196ada4a1 100644 --- a/src/test/java/chess/repository/fake/WhitePieceRepository.java +++ b/src/test/java/chess/repository/fake/WhitePieceRepository.java @@ -30,12 +30,17 @@ public Piece findPieceByPosition(Position position, Long roomId) { @Override public List findPieceByColor(Color piece_color, Long roomId) { - return null; + return List.of( + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.WHITE_PAWN, Color.WHITE), + new Piece(PieceType.ROOK, Color.WHITE)); } @Override public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { - return null; + return List.of(2, 2); } @Override @@ -45,6 +50,6 @@ public Map findAllPieceByRoomId(Long roomId) { @Override public List findPieceByPieceType(PieceType pieceType, Long roomId) { - return null; + return List.of(new Piece(PieceType.KING, Color.WHITE)); } } From ba433da98e6185e8533fdff8974980ad771805ab Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 23:39:47 +0900 Subject: [PATCH 14/18] =?UTF-8?q?test:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/chess/service/BoardServiceTest.java | 64 +++++++++++++++++++ .../java/chess/service/GameServiceTest.java | 59 +++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/test/java/chess/service/BoardServiceTest.java create mode 100644 src/test/java/chess/service/GameServiceTest.java diff --git a/src/test/java/chess/service/BoardServiceTest.java b/src/test/java/chess/service/BoardServiceTest.java new file mode 100644 index 00000000000..2a078d138f3 --- /dev/null +++ b/src/test/java/chess/service/BoardServiceTest.java @@ -0,0 +1,64 @@ +package chess.service; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.domain.board.position.Column; +import chess.domain.board.position.Position; +import chess.domain.board.position.Row; +import chess.repository.BoardRepository; +import chess.repository.RoomRepository; +import chess.repository.fake.FakeBoardRepository; +import chess.repository.fake.FakeRoomRepository; +import chess.repository.fake.NotExistsPieceRepository; +import chess.repository.fake.WhitePieceRepository; +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 BoardServiceTest { + + private RoomRepository roomRepository; + private Position from; + private Position to; + + @BeforeEach + void setUp() { + roomRepository = new FakeRoomRepository(); + from = new Position(Row.TWO, Column.C); + to = new Position(Row.THREE, Column.C); + } + + @DisplayName("선택한 위치에 기물이 존재하지 않으면 에러를 반환한다.") + @Test + void findFromPositionPieceTest() { + BoardRepository boardRepository = new NotExistsPieceRepository(); + BoardService boardService = new BoardService(roomRepository, boardRepository); + + assertThatThrownBy(() -> boardService.movePiece(from, to, 0L)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("선택한 기물이 존재하지 않습니다."); + } + + @DisplayName("이동시키려는 기물이 상대 기물이면 에러를 반환한다.") + @Test + void findCurrentTurnTest() { + BoardRepository boardRepository = new WhitePieceRepository(); + BoardService boardService = new BoardService(roomRepository, boardRepository); + + assertThatThrownBy(() -> boardService.movePiece(from, to, 0L)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("상대방의 기물을 움직일 수 없습니다. 현재 턴 : BLACK"); + } + + @DisplayName("이동 위치에 기물이 존재하고, 조회한 기물 타입이 킹이면 참을 반환한다.") + @Test + void isCheckmateTest() { + BoardRepository boardRepository = new FakeBoardRepository(); + BoardService boardService = new BoardService(roomRepository, boardRepository); + + boolean isCheckmate = boardService.isCheckmate(from, 0L); + + Assertions.assertThat(isCheckmate).isTrue(); + } +} diff --git a/src/test/java/chess/service/GameServiceTest.java b/src/test/java/chess/service/GameServiceTest.java new file mode 100644 index 00000000000..14fc9a8bfdc --- /dev/null +++ b/src/test/java/chess/service/GameServiceTest.java @@ -0,0 +1,59 @@ +package chess.service; + +import static org.assertj.core.api.Assertions.assertThat; + +import chess.domain.game.Score; +import chess.domain.game.Winner; +import chess.domain.piece.Color; +import chess.repository.BoardRepository; +import chess.repository.RoomRepository; +import chess.repository.fake.FakeBoardRepository; +import chess.repository.fake.FakeRoomRepository; +import chess.repository.fake.WhitePieceRepository; +import chess.service.dto.ChessGameResult; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class GameServiceTest { + + private RoomRepository roomRepository; + private BoardRepository boardRepository; + + @BeforeEach + void setUp() { + roomRepository = new FakeRoomRepository(); + boardRepository = new FakeBoardRepository(); + } + + @DisplayName("점수를 계산하여 반환한다.") + @Test + void getScoreTest() { + GameService gameService = new GameService(roomRepository, boardRepository); + + Map score = gameService.getScore(0L); + + assertThat(score.get(Color.WHITE).score()).isEqualTo(7); + } + + @DisplayName("살아있는 킹의 수가 2개일 때 점수를 이용하여 게임 결과를 생성한다.") + @Test + void generateGameResultTestWithScore() { + GameService gameService = new GameService(roomRepository, boardRepository); + + ChessGameResult chessGameResult = gameService.generateGameResult(0L); + + assertThat(chessGameResult.getWinner()).isEqualTo(Winner.DRAW); + } + + @DisplayName("살아있는 킹의 수가 1개일 때 킹의 색을 확인하고 게임 결과를 생성한다.") + @Test + void generateGameResultTestWithCheckmate() { + GameService gameService = new GameService(roomRepository, new WhitePieceRepository()); + + ChessGameResult chessGameResult = gameService.generateGameResult(0L); + + assertThat(chessGameResult.getWinner()).isEqualTo(Winner.WHITE_WIN); + } +} From d144ce7e3b0fba626484d415ab30b13cd01de2a2 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Sun, 31 Mar 2024 23:40:37 +0900 Subject: [PATCH 15/18] =?UTF-8?q?refactor:=20fake=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=A3=BC=EC=9E=85=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chess/controller/command/EndTest.java | 18 ++++++++++++++++-- .../chess/controller/command/MoveTest.java | 11 ----------- .../chess/controller/command/StartTest.java | 18 ++++++++++++++++-- .../chess/controller/command/StatusTest.java | 19 ++++++++++++++++--- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/test/java/chess/controller/command/EndTest.java b/src/test/java/chess/controller/command/EndTest.java index db4db13ac0e..b52ce9733c2 100644 --- a/src/test/java/chess/controller/command/EndTest.java +++ b/src/test/java/chess/controller/command/EndTest.java @@ -5,14 +5,28 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import chess.controller.State; +import chess.repository.BoardRepository; +import chess.repository.RoomRepository; +import chess.repository.fake.FakeBoardRepository; +import chess.repository.fake.FakeRoomRepository; import chess.service.BoardService; import chess.service.GameService; import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class EndTest { + private RoomRepository roomRepository; + private BoardRepository boardRepository; + + @BeforeEach + void setUp() { + roomRepository = new FakeRoomRepository(); + boardRepository = new FakeBoardRepository(); + } + @DisplayName("명령어 입력이 end로만 이루어져 있으면 정상적으로 생성된다.") @Test void validateCommandInputSizeSuccessTest() { @@ -32,8 +46,8 @@ void validateCommandInputSizeFailTest() { @Test void executeTest() { End end = new End(List.of("end")); - GameService gameService = new GameService(); - BoardService boardService = new BoardService(); + GameService gameService = new GameService(roomRepository, boardRepository); + BoardService boardService = new BoardService(roomRepository, boardRepository); State gameState = end.execute(gameService, boardService, 0L); diff --git a/src/test/java/chess/controller/command/MoveTest.java b/src/test/java/chess/controller/command/MoveTest.java index 33d5db595d5..23d5060b509 100644 --- a/src/test/java/chess/controller/command/MoveTest.java +++ b/src/test/java/chess/controller/command/MoveTest.java @@ -23,15 +23,4 @@ void validateCommandInputSizeFailTest() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("게임 이동 명령어 입력 형식이 올바르지 않습니다."); } -// -// @DisplayName("기능을 수행한 후 RUNNING 상태를 반환한다.") -// @Test -// void executeTest() { -// Move move = new Move(List.of("move", "b2", "b4")); -// GameService gameService = new GameService(); -// BoardService boardService = new BoardService(); -// State gameState = move.execute(gameService, boardService, 0L); -// -// assertThat(gameState).isEqualTo(State.RUNNING); -// } } diff --git a/src/test/java/chess/controller/command/StartTest.java b/src/test/java/chess/controller/command/StartTest.java index bc64900f654..ba4188c7312 100644 --- a/src/test/java/chess/controller/command/StartTest.java +++ b/src/test/java/chess/controller/command/StartTest.java @@ -5,14 +5,28 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import chess.controller.State; +import chess.repository.BoardRepository; +import chess.repository.RoomRepository; +import chess.repository.fake.FakeBoardRepository; +import chess.repository.fake.FakeRoomRepository; import chess.service.BoardService; import chess.service.GameService; import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class StartTest { + private RoomRepository roomRepository; + private BoardRepository boardRepository; + + @BeforeEach + void setUp() { + roomRepository = new FakeRoomRepository(); + boardRepository = new FakeBoardRepository(); + } + @DisplayName("명령어 입력이 start로만 이루어져 있으면 정상적으로 생성된다.") @Test void validateCommandInputSize() { @@ -32,8 +46,8 @@ void validateCommandInputSizeFailTest() { @Test void executeTest() { Start start = new Start(List.of("start")); - GameService gameService = new GameService(); - BoardService boardService = new BoardService(); + GameService gameService = new GameService(roomRepository, boardRepository); + BoardService boardService = new BoardService(roomRepository, boardRepository); State gameState = start.execute(gameService, boardService, 0L); assertThat(gameState).isEqualTo(State.RUNNING); diff --git a/src/test/java/chess/controller/command/StatusTest.java b/src/test/java/chess/controller/command/StatusTest.java index d2d8f76d912..d89ec80f2a5 100644 --- a/src/test/java/chess/controller/command/StatusTest.java +++ b/src/test/java/chess/controller/command/StatusTest.java @@ -5,14 +5,28 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import chess.controller.State; +import chess.repository.BoardRepository; +import chess.repository.RoomRepository; +import chess.repository.fake.FakeBoardRepository; +import chess.repository.fake.FakeRoomRepository; import chess.service.BoardService; import chess.service.GameService; import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class StatusTest { + private RoomRepository roomRepository; + private BoardRepository boardRepository; + + @BeforeEach + void setUp() { + roomRepository = new FakeRoomRepository(); + boardRepository = new FakeBoardRepository(); + } + @DisplayName("명령어 입력이 status로만 이루어져 있으면 정상적으로 생성된다.") @Test void validateCommandInputSizeSuccessTest() { @@ -32,11 +46,10 @@ void validateCommandInputSizeFailTest() { @Test void executeTest() { Status status = new Status(List.of("status")); - GameService gameService = new GameService(); - BoardService boardService = new BoardService(); + GameService gameService = new GameService(roomRepository, boardRepository); + BoardService boardService = new BoardService(roomRepository, boardRepository); State gameState = status.execute(gameService, boardService, 0L); assertThat(gameState).isEqualTo(State.RUNNING); } - } From 3d97e2d3aaabf0a9437180e9b71efb9e9a0b80dc Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Mon, 1 Apr 2024 00:18:17 +0900 Subject: [PATCH 16/18] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3543b7541ef..6b7e68795d0 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ ## 체스 기물 - ### 방향 - [X] : 북, 북동, 동, 동남, 남, 남서, 서, 북서쪽의 총 8방향을 갖는다. - [X] : 방향에 따라 방향 가중치 (1, -1, 0)을 갖는다. @@ -43,10 +42,19 @@ ### 기물 타입 - [X] : 기물 타입은 이동 전략을 갖는다. - - [X] : 각 기물의 이동 전략 구현체는 기물의 현재 위치, 방향, 가중치를 가지고 이동할 수 있는 위치들을 계산한다. + - [X] : 각 기물의 이동 전략 구현체는 기물의 현재 위치, 방향, 가중치를 가지고 이동할 수 있는 후보 위치들을 계산한다. - [X] : 룩은 기본적으로 북, 동, 남, 서 방향으로 이동할 수 있다. - [X] : 비숍은 기본적으로 북동, 동남, 남서, 북서 방향으로 이동할 수 있다. - [X] : 퀸은 기본적으로 모든 방향으로 이동할 수 있다. - [X] : 킹은 기본적으로 모든 방향으로 이동할 수 있다. - [X] : 폰은 기본적으로 팀 색깔에 따라 북 또는 남 방향으로만 이동할 수 있다. - [X] : 나이트는 기본적으로 북북동, 동북동, 동남동, 남남동, 남남서, 서남서, 서북서, 북북서 방향으로 이동할 수 있다. + +## 기물 이동 + - [X] : 각 기물이 생성한 후보 위치를 이용하여 실제 이동 가능한 위치인지 판단한다. + - [X] : 위치에 기물이 존재하지 않으면 이동 가능한 위치이므로 포함한다. + - [X] : 위치에 우리팀 기물이 존재할 경우 이동할 수 없는 위치이므로 포함하지 않고 다음 방향으로 넘어간다. + - [X] : 위치에 상대팀 기물이 존재할 경우 이동가능한 위치이므로 포함하고 다음 방향으로 넘어간다. + - [X] : 명령어 입력으로 들어온 목적지 위치가 실제 이동 가능한 위치인지 판단한다. + - [X] : 실제 이동 가능한 위치에 포함되어 있는 경우 이동한다. + - [X] : 실제 이동 가능한 위치에 포함되어 있지 않은 경우 에러를 발생시킨다. From c9d56779edfc4d62add28a18b3132423018b0661 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Mon, 1 Apr 2024 00:32:56 +0900 Subject: [PATCH 17/18] =?UTF-8?q?refactor:=20repository=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chess/repository/BoardRepository.java | 2 +- .../chess/repository/BoardRepositoryImpl.java | 61 ++++++++++++------- .../chess/repository/RoomRepositoryImpl.java | 40 ++++++++---- src/main/java/chess/service/GameService.java | 2 +- .../repository/fake/BlackPieceRepository.java | 2 +- .../repository/fake/FakeBoardRepository.java | 2 +- .../fake/NotExistsPieceRepository.java | 2 +- .../repository/fake/WhitePieceRepository.java | 2 +- 8 files changed, 73 insertions(+), 40 deletions(-) diff --git a/src/main/java/chess/repository/BoardRepository.java b/src/main/java/chess/repository/BoardRepository.java index ce80531be57..b7904430e75 100644 --- a/src/main/java/chess/repository/BoardRepository.java +++ b/src/main/java/chess/repository/BoardRepository.java @@ -17,7 +17,7 @@ public interface BoardRepository { Piece findPieceByPosition(Position position, Long roomId); - List findPieceByColor(Color piece_color, Long roomId); + List findPiecesByColor(Color piece_color, Long roomId); List getPieceCountByPieceType(PieceType pieceType, Long roomId); diff --git a/src/main/java/chess/repository/BoardRepositoryImpl.java b/src/main/java/chess/repository/BoardRepositoryImpl.java index daa56d3a3bf..34e6b2d6cde 100644 --- a/src/main/java/chess/repository/BoardRepositoryImpl.java +++ b/src/main/java/chess/repository/BoardRepositoryImpl.java @@ -40,13 +40,17 @@ public boolean existsPieceByPosition(Position position, Long roomId) { preparedStatement.setString(2, position.getColumn().name()); preparedStatement.setLong(3, roomId); ResultSet rs = preparedStatement.executeQuery(); - if (rs.next()) { - existsPiece.add(rs.getBoolean("exists_piece")); - } + addExistPieceResult(existsPiece, rs); }); return existsPiece.get(0); } + private void addExistPieceResult(List existsPiece, ResultSet rs) throws SQLException { + if (rs.next()) { + existsPiece.add(rs.getBoolean("exists_piece")); + } + } + @Override public void deletePieceByPosition(Position position, Long roomId) { final String query = "DELETE FROM board WHERE `row` = ? AND `column` = ? AND room_id = ?"; @@ -67,29 +71,36 @@ public Piece findPieceByPosition(Position position, Long roomId) { preparedStatement.setString(2, position.getColumn().name()); preparedStatement.setLong(3, roomId); ResultSet rs = preparedStatement.executeQuery(); - if (rs.next()) { - pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); - } + addPiece(pieces, rs); }); return pieces.get(0); } + private void addPiece(List pieces, ResultSet rs) throws SQLException { + if (rs.next()) { + pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); + } + } + @Override - public List findPieceByColor(Color piece_color, Long roomId) { + public List findPiecesByColor(Color piece_color, Long roomId) { List pieces = new ArrayList<>(); String query = "SELECT piece_type, piece_color FROM board WHERE piece_color = ? AND room_id = ?"; processQuery(query, preparedStatement -> { preparedStatement.setString(1, piece_color.name()); preparedStatement.setLong(2, roomId); ResultSet rs = preparedStatement.executeQuery(); - while (rs.next()) { - Piece piece = new Piece(rs.getString("piece_type"), rs.getString("piece_color")); - pieces.add(piece); - } + addPieces(pieces, rs); }); return pieces; } + private void addPieces(List pieces, ResultSet rs) throws SQLException { + while (rs.next()) { + pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); + } + } + @Override public List getPieceCountByPieceType(PieceType pieceType, Long roomId) { List pieceCount = new ArrayList<>(); @@ -98,13 +109,17 @@ public List getPieceCountByPieceType(PieceType pieceType, Long roomId) preparedStatement.setString(1, pieceType.name()); preparedStatement.setLong(2, roomId); ResultSet rs = preparedStatement.executeQuery(); - while (rs.next()) { - pieceCount.add(rs.getInt("piece_count")); - } + addPieceCount(pieceCount, rs); }); return pieceCount; } + private void addPieceCount(List pieceCount, ResultSet rs) throws SQLException { + while (rs.next()) { + pieceCount.add(rs.getInt("piece_count")); + } + } + @Override public Map findAllPieceByRoomId(Long roomId) { Map allPieces = new HashMap<>(); @@ -112,15 +127,19 @@ public Map findAllPieceByRoomId(Long roomId) { processQuery(query, preparedStatement -> { preparedStatement.setLong(1, roomId); ResultSet rs = preparedStatement.executeQuery(); - while (rs.next()) { - Position position = new Position(rs.getInt("row"), rs.getString("column")); - Piece piece = new Piece(rs.getString("piece_type"), rs.getString("piece_color")); - allPieces.put(position, piece); - } + addPositionPieces(allPieces, rs); }); return allPieces; } + private void addPositionPieces(Map allPieces, ResultSet rs) throws SQLException { + while (rs.next()) { + Position position = new Position(rs.getInt("row"), rs.getString("column")); + Piece piece = new Piece(rs.getString("piece_type"), rs.getString("piece_color")); + allPieces.put(position, piece); + } + } + @Override public List findPieceByPieceType(PieceType pieceType, Long roomId) { List pieces = new ArrayList<>(); @@ -129,9 +148,7 @@ public List findPieceByPieceType(PieceType pieceType, Long roomId) { preparedStatement.setString(1, pieceType.name()); preparedStatement.setLong(2, roomId); ResultSet rs = preparedStatement.executeQuery(); - while (rs.next()) { - pieces.add(new Piece(rs.getString("piece_type"), rs.getString("piece_color"))); - } + addPieces(pieces, rs); }); return pieces; } diff --git a/src/main/java/chess/repository/RoomRepositoryImpl.java b/src/main/java/chess/repository/RoomRepositoryImpl.java index aca205e3815..176878c35c7 100644 --- a/src/main/java/chess/repository/RoomRepositoryImpl.java +++ b/src/main/java/chess/repository/RoomRepositoryImpl.java @@ -20,13 +20,17 @@ public List findAllRoomNames() { String query = "SELECT name FROM room"; processQuery(query, preparedStatement -> { ResultSet rs = preparedStatement.executeQuery(); - while (rs.next()) { - allRoomNames.add(rs.getString("name")); - } + addRoomNames(allRoomNames, rs); }); return allRoomNames; } + private void addRoomNames(List allRoomNames, ResultSet rs) throws SQLException { + while (rs.next()) { + allRoomNames.add(rs.getString("name")); + } + } + @Override public boolean existsRoomName(RoomName roomName) { List existsRoom = new ArrayList<>(); @@ -35,13 +39,17 @@ public boolean existsRoomName(RoomName roomName) { processQuery(query, preparedStatement -> { preparedStatement.setString(1, roomName.getValue()); ResultSet rs = preparedStatement.executeQuery(); - if (rs.next()) { - existsRoom.add(rs.getBoolean("exists_room")); - } + addExistsRoomResult(existsRoom, rs); }); return existsRoom.get(0); } + private void addExistsRoomResult(List existsRoom, ResultSet rs) throws SQLException { + if (rs.next()) { + existsRoom.add(rs.getBoolean("exists_room")); + } + } + @Override public void saveRoom(RoomName roomName) { final String query = "INSERT INTO room(name, turn) VALUES(?, ?)"; @@ -69,13 +77,17 @@ public Room findRoomByName(RoomName roomName) { processQuery(query, preparedStatement -> { preparedStatement.setString(1, roomName.getValue()); ResultSet rs = preparedStatement.executeQuery(); - if (rs.next()) { - roomId.add(new Room(rs.getLong("id"), rs.getString("name"))); - } + addRoom(roomId, rs); }); return roomId.get(0); } + private void addRoom(List roomId, ResultSet rs) throws SQLException { + if (rs.next()) { + roomId.add(new Room(rs.getLong("id"), rs.getString("name"))); + } + } + @Override public Color findTurnById(Long roomId) { List color = new ArrayList<>(); @@ -83,13 +95,17 @@ public Color findTurnById(Long roomId) { processQuery(query, preparedStatement -> { preparedStatement.setLong(1, roomId); ResultSet rs = preparedStatement.executeQuery(); - if (rs.next()) { - color.add(Color.valueOf(rs.getString("turn"))); - } + addColor(color, rs); }); return color.get(0); } + private void addColor(List color, ResultSet rs) throws SQLException { + if (rs.next()) { + color.add(Color.valueOf(rs.getString("turn"))); + } + } + private void processQuery(String query, QueryProcessor queryProcessor) { try (final Connection connection = dbConnection.getConnection()) { final PreparedStatement preparedStatement = connection.prepareStatement(query); diff --git a/src/main/java/chess/service/GameService.java b/src/main/java/chess/service/GameService.java index 471277adbf9..ea525015488 100644 --- a/src/main/java/chess/service/GameService.java +++ b/src/main/java/chess/service/GameService.java @@ -78,7 +78,7 @@ private Score calculateTotalScore(Color color, PieceType pieceType, Long roomId) } private double sumTotalScore(Color color, Long roomId) { - List pieces = boardRepository.findPieceByColor(color, roomId); + List pieces = boardRepository.findPiecesByColor(color, roomId); return pieces.stream() .mapToDouble(Piece::getScore) .sum(); diff --git a/src/test/java/chess/repository/fake/BlackPieceRepository.java b/src/test/java/chess/repository/fake/BlackPieceRepository.java index 933843e6b68..5721a27ffd5 100644 --- a/src/test/java/chess/repository/fake/BlackPieceRepository.java +++ b/src/test/java/chess/repository/fake/BlackPieceRepository.java @@ -29,7 +29,7 @@ public Piece findPieceByPosition(Position position, Long roomId) { } @Override - public List findPieceByColor(Color piece_color, Long roomId) { + public List findPiecesByColor(Color piece_color, Long roomId) { return null; } diff --git a/src/test/java/chess/repository/fake/FakeBoardRepository.java b/src/test/java/chess/repository/fake/FakeBoardRepository.java index e56de498c6d..635bd6afbb7 100644 --- a/src/test/java/chess/repository/fake/FakeBoardRepository.java +++ b/src/test/java/chess/repository/fake/FakeBoardRepository.java @@ -32,7 +32,7 @@ public Piece findPieceByPosition(Position position, Long roomId) { } @Override - public List findPieceByColor(Color piece_color, Long roomId) { + public List findPiecesByColor(Color piece_color, Long roomId) { return List.of( new Piece(PieceType.WHITE_PAWN, Color.WHITE), new Piece(PieceType.WHITE_PAWN, Color.WHITE), diff --git a/src/test/java/chess/repository/fake/NotExistsPieceRepository.java b/src/test/java/chess/repository/fake/NotExistsPieceRepository.java index 63b2ca9fa5a..dc86c643f05 100644 --- a/src/test/java/chess/repository/fake/NotExistsPieceRepository.java +++ b/src/test/java/chess/repository/fake/NotExistsPieceRepository.java @@ -29,7 +29,7 @@ public Piece findPieceByPosition(Position position, Long roomId) { } @Override - public List findPieceByColor(Color piece_color, Long roomId) { + public List findPiecesByColor(Color piece_color, Long roomId) { return null; } diff --git a/src/test/java/chess/repository/fake/WhitePieceRepository.java b/src/test/java/chess/repository/fake/WhitePieceRepository.java index 38196ada4a1..3e7f3c2c65a 100644 --- a/src/test/java/chess/repository/fake/WhitePieceRepository.java +++ b/src/test/java/chess/repository/fake/WhitePieceRepository.java @@ -29,7 +29,7 @@ public Piece findPieceByPosition(Position position, Long roomId) { } @Override - public List findPieceByColor(Color piece_color, Long roomId) { + public List findPiecesByColor(Color piece_color, Long roomId) { return List.of( new Piece(PieceType.WHITE_PAWN, Color.WHITE), new Piece(PieceType.WHITE_PAWN, Color.WHITE), From 6ba1c2dcf786dc01fb6aa71ef66494054f955f70 Mon Sep 17 00:00:00 2001 From: seokmyungham Date: Mon, 1 Apr 2024 00:36:16 +0900 Subject: [PATCH 18/18] =?UTF-8?q?refactor(OutputView):=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=ED=8F=AC=EB=A7=B7=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/view/OutputView.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java index 3d524df2a88..e6f4fa45327 100644 --- a/src/main/java/chess/view/OutputView.java +++ b/src/main/java/chess/view/OutputView.java @@ -63,24 +63,21 @@ public static void printBoard(Map board) { public static void printChessGameResult(ChessGameResult chessGameResult) { System.out.print("왕이 죽어서 게임이 종료되었습니다. \n체스 게임 결과 : "); Winner winner = chessGameResult.getWinner(); - Map teamScore = chessGameResult.getTeamScore(); - Score whiteScore = teamScore.get(Color.WHITE); - Score blackScore = teamScore.get(Color.BLACK); if (winner == Winner.WHITE_WIN) { System.out.println("흰색이 검은색 왕을 죽이고 승리하였습니다."); } if (winner == Winner.BLACK_WIN) { System.out.println("검은색이 흰색 왕을 죽이고 승리하였습니다."); } - printScore(whiteScore, blackScore); + + Map teamScore = chessGameResult.getTeamScore(); + printScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); } public static void printTeamScore(ChessGameResult chessGameResult) { Winner winner = chessGameResult.getWinner(); Map teamScore = chessGameResult.getTeamScore(); - Score whiteScore = teamScore.get(Color.WHITE); - Score blackScore = teamScore.get(Color.BLACK); - printScore(whiteScore, blackScore); + printScore(teamScore.get(Color.WHITE), teamScore.get(Color.BLACK)); if (winner == Winner.WHITE_WIN) { System.out.println("현재 대국 상황은 흰색이 우세합니다.");