From 441187d6a4341f24c087e4b2b18a05fc7acd7450 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 14:23:31 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat=20:=20=ED=8F=B0=20=EB=B6=81=EC=AA=BD?= =?UTF-8?q?=20=EB=B0=A9=ED=96=A5=20=EC=9B=80=EC=A7=81=EC=9E=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Board.java | 20 ++++++++ src/main/java/chess/Position.java | 13 +++++ src/main/java/chess/Row.java | 2 +- src/main/java/chess/piece/Bishop.java | 7 ++- src/main/java/chess/piece/King.java | 8 ++- src/main/java/chess/piece/Knight.java | 8 ++- src/main/java/chess/piece/Pawn.java | 66 ++++++++++++++++++++++++- src/main/java/chess/piece/Piece.java | 7 +++ src/main/java/chess/piece/Queen.java | 7 ++- src/main/java/chess/piece/Rook.java | 8 ++- src/test/java/chess/piece/PawnTest.java | 51 +++++++++++++++++++ 11 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 src/main/java/chess/Board.java create mode 100644 src/main/java/chess/piece/Piece.java create mode 100644 src/test/java/chess/piece/PawnTest.java diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java new file mode 100644 index 00000000000..4d78366f01a --- /dev/null +++ b/src/main/java/chess/Board.java @@ -0,0 +1,20 @@ +package chess; + +import chess.piece.Piece; +import java.util.List; +import java.util.Optional; + +public class Board { + private final List pieces; + + public Board(List pieces) { + this.pieces = pieces; + } + + + public Optional findByPosition(Position newPosition) { + return pieces.stream() + .filter(piece -> piece.isPositionEquals(newPosition)) + .findFirst(); + } +} diff --git a/src/main/java/chess/Position.java b/src/main/java/chess/Position.java index 3ebeb0ea185..f97828159eb 100644 --- a/src/main/java/chess/Position.java +++ b/src/main/java/chess/Position.java @@ -167,4 +167,17 @@ public Position moveHorizontal(final int step) { } return this; } + + ///// + public boolean isRowOrdinalBiggerThan(Position targetPostion, int upperBoundGap) { + return this.row.ordinal() >= (targetPostion.row.ordinal() + upperBoundGap); + } + + public boolean isRowEquals(Row row) { + return this.row == row; + } + + public int calculateRowGap(Position targetPosition) { + return this.row.ordinal() - targetPosition.row.ordinal(); + } } diff --git a/src/main/java/chess/Row.java b/src/main/java/chess/Row.java index 126ed048daa..60f63fa3567 100644 --- a/src/main/java/chess/Row.java +++ b/src/main/java/chess/Row.java @@ -2,7 +2,7 @@ public enum Row { - EIGHT, + EIGHT, // 0 SEVEN, SIX, FIVE, diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index b14ab70f981..981be8d0502 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -1,5 +1,10 @@ package chess.piece; -public class Bishop { +import chess.Position; +public class Bishop implements Piece{ + @Override + public boolean isPositionEquals(Position targetPosition) { + return false; + } } diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index d64210cad13..179ddfcc8f5 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -1,5 +1,11 @@ package chess.piece; -public class King { +import chess.Position; + +public class King implements Piece { + @Override + public boolean isPositionEquals(Position targetPosition) { + return false; + } } diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 2ee7c47a3bc..b4eff364c9a 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -1,5 +1,11 @@ package chess.piece; -public class Knight { +import chess.Position; + +public class Knight implements Piece { + @Override + public boolean isPositionEquals(Position targetPosition) { + return false; + } } diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index c8b6cafa51e..3ee1f2c0adb 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -1,5 +1,69 @@ package chess.piece; -public class Pawn { +import chess.Board; +import chess.Color; +import chess.Position; +import chess.Row; +import java.util.Objects; +public class Pawn implements Piece { + private final Color color; + private Position position; + + public Pawn(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void moveUp(Position targetPosition, Board board) { + int step = position.calculateRowGap(targetPosition); + if (isMovingInitially() && step <= 2) { //초기 움직임 + repeateMoveUp(board, step); + return; + } + if (step >= 2) { + throw new IllegalArgumentException("폰은 2칸 이상 전진할 수 없습니다."); + } + repeateMoveUp(board, step); + } + + private void repeateMoveUp(Board board, int step) { + for (int s = 0; s < step; s++) { + Position newPosition = this.position.moveUp(); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + } + + private boolean isMovingInitially() { + if (color.isWhite()) { + return position.isRowEquals(Row.TWO); + } + return position.isRowEquals(Row.SEVEN); + } + + @Override + public boolean isPositionEquals(Position targetPosition) { + return this.position.equals(targetPosition); + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pawn pawn = (Pawn) o; + return color == pawn.color && Objects.equals(position, pawn.position); + } + + @Override + public int hashCode() { + return Objects.hash(color, position); + } } diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java new file mode 100644 index 00000000000..fb00a4c19fb --- /dev/null +++ b/src/main/java/chess/piece/Piece.java @@ -0,0 +1,7 @@ +package chess.piece; + +import chess.Position; + +public interface Piece { + boolean isPositionEquals(Position targetPosition); +} diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 9b547261c4b..909de1ad5f9 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -1,5 +1,10 @@ package chess.piece; -public class Queen { +import chess.Position; +public class Queen implements Piece { + @Override + public boolean isPositionEquals(Position targetPosition) { + return false; + } } diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 7ed4d08bf03..a55148941c5 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -1,5 +1,11 @@ package chess.piece; -public class Rook { +import chess.Position; +public class Rook implements Piece { + @Override + public boolean isPositionEquals(Position targetPosition) { + return false; + } } + diff --git a/src/test/java/chess/piece/PawnTest.java b/src/test/java/chess/piece/PawnTest.java new file mode 100644 index 00000000000..b2d31a087b2 --- /dev/null +++ b/src/test/java/chess/piece/PawnTest.java @@ -0,0 +1,51 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class PawnTest { + + private Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); + private Board board = new Board(List.of( + pawn + )); + + @Test + void moveUpOnce() { + pawn.moveUp(new Position(Column.A, Row.THREE), board); + + assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.THREE))); + } + + @Test + void failToMoveUpMoreThanOnce() { + assertThatThrownBy(() -> pawn.moveUp(new Position(Column.A, Row.FIVE), board)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void moveUpTwiceIfStartMoving() { + pawn.moveUp(new Position(Column.A, Row.FOUR), board); + + assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.FOUR))); + } + + @Test + void failIfHurdleExists() { + Board hurdleBoard = new Board(List.of( + new Pawn(Color.BLACK, new Position(Column.A, Row.THREE)), + pawn + )); + + assertThatThrownBy(() -> pawn.moveUp(new Position(Column.A, Row.FOUR), hurdleBoard)) + .isInstanceOf(IllegalArgumentException.class); + } +} From 4891c12f63f72cb27068b577494ee9612a1fc66e Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 14:44:35 +0900 Subject: [PATCH 02/19] =?UTF-8?q?feat=20:=20=ED=8F=B0=20=EB=8F=99=EC=84=9C?= =?UTF-8?q?=EB=82=A8=EB=B6=81=20=EB=B0=A9=ED=96=A5=20=EC=9B=80=EC=A7=81?= =?UTF-8?q?=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Position.java | 15 ++++++--- src/main/java/chess/piece/Pawn.java | 35 ++++++++++++++++----- src/test/java/chess/piece/PawnTest.java | 41 +++++++++++++++++++------ 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/main/java/chess/Position.java b/src/main/java/chess/Position.java index f97828159eb..4d0c1efa9e8 100644 --- a/src/main/java/chess/Position.java +++ b/src/main/java/chess/Position.java @@ -169,15 +169,22 @@ public Position moveHorizontal(final int step) { } ///// - public boolean isRowOrdinalBiggerThan(Position targetPostion, int upperBoundGap) { - return this.row.ordinal() >= (targetPostion.row.ordinal() + upperBoundGap); + + public boolean isRowEquals(Position targetPosition) { + return this.row == targetPosition.row; } - public boolean isRowEquals(Row row) { - return this.row == row; + public boolean isColumnEquals(Position targetPosition) { + return this.column == targetPosition.column; } public int calculateRowGap(Position targetPosition) { return this.row.ordinal() - targetPosition.row.ordinal(); } + + public int calculateColumnGap(Position targetPosition) { + return this.column.ordinal() - targetPosition.column.ordinal(); + } + + } diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 3ee1f2c0adb..e194456e7bc 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -2,6 +2,8 @@ import chess.Board; import chess.Color; +import chess.Column; +import chess.Movement; import chess.Position; import chess.Row; import java.util.Objects; @@ -15,21 +17,38 @@ public Pawn(Color color, Position position) { this.position = position; } - public void moveUp(Position targetPosition, Board board) { - int step = position.calculateRowGap(targetPosition); + public void move(Position targetPosition, Board board) { + Movement movement = findMovement(targetPosition); + int step = Math.abs(position.calculateRowGap(targetPosition)); if (isMovingInitially() && step <= 2) { //초기 움직임 - repeateMoveUp(board, step); + repeatMove(movement, board, step); return; } if (step >= 2) { throw new IllegalArgumentException("폰은 2칸 이상 전진할 수 없습니다."); } - repeateMoveUp(board, step); + repeatMove(movement, board, step); } - private void repeateMoveUp(Board board, int step) { + private Movement findMovement(Position targetPosition) { + if (position.isRowEquals(targetPosition)) { + if (position.calculateColumnGap(targetPosition) > 0) { + return Movement.LEFT; + } + return Movement.RIGHT; + } + if (position.isColumnEquals(targetPosition)) { + if (position.calculateRowGap(targetPosition) > 0) { + return Movement.UP; + } + return Movement.DOWN; + } + throw new IllegalArgumentException("폰은 동서남북 방향으로만 이동 가능합니다."); + } + + private void repeatMove(Movement movement, Board board, int step) { for (int s = 0; s < step; s++) { - Position newPosition = this.position.moveUp(); + Position newPosition = this.position.move(movement); if (board.findByPosition(newPosition).isPresent()) { throw new IllegalArgumentException("장애물이 존재합니다."); } @@ -39,9 +58,9 @@ private void repeateMoveUp(Board board, int step) { private boolean isMovingInitially() { if (color.isWhite()) { - return position.isRowEquals(Row.TWO); + return position.isRowEquals(new Position(Column.A, Row.TWO)); } - return position.isRowEquals(Row.SEVEN); + return position.isRowEquals(new Position(Column.A, Row.SEVEN)); } @Override diff --git a/src/test/java/chess/piece/PawnTest.java b/src/test/java/chess/piece/PawnTest.java index b2d31a087b2..1d3766c0eba 100644 --- a/src/test/java/chess/piece/PawnTest.java +++ b/src/test/java/chess/piece/PawnTest.java @@ -13,39 +13,62 @@ public class PawnTest { - private Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); - private Board board = new Board(List.of( - pawn - )); - @Test void moveUpOnce() { - pawn.moveUp(new Position(Column.A, Row.THREE), board); + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); + Board board = new Board(List.of( + pawn + )); + + pawn.move(new Position(Column.A, Row.THREE), board); assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.THREE))); } @Test void failToMoveUpMoreThanOnce() { - assertThatThrownBy(() -> pawn.moveUp(new Position(Column.A, Row.FIVE), board)) + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); + Board board = new Board(List.of( + pawn + )); + + assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.FIVE), board)) .isInstanceOf(IllegalArgumentException.class); } @Test void moveUpTwiceIfStartMoving() { - pawn.moveUp(new Position(Column.A, Row.FOUR), board); + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); + Board board = new Board(List.of( + pawn + )); + + pawn.move(new Position(Column.A, Row.FOUR), board); assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.FOUR))); } @Test void failIfHurdleExists() { + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); Board hurdleBoard = new Board(List.of( new Pawn(Color.BLACK, new Position(Column.A, Row.THREE)), pawn )); - assertThatThrownBy(() -> pawn.moveUp(new Position(Column.A, Row.FOUR), hurdleBoard)) + assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.FOUR), hurdleBoard)) .isInstanceOf(IllegalArgumentException.class); } + + @Test + void moveDownOnce() { + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.THREE)); + Board board = new Board(List.of( + pawn + )); + + pawn.move(new Position(Column.A, Row.TWO), board); + + assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.TWO))); + } } From ea3f86126dcbfe962a21d5602b4b00650600c9be Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 14:48:04 +0900 Subject: [PATCH 03/19] =?UTF-8?q?feat=20:=20=ED=8F=B0=20=EC=9B=80=EC=A7=81?= =?UTF-8?q?=EC=9E=84=20=EC=A4=91=20=EC=98=88=EC=99=B8=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EA=B5=AC=EC=B2=B4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Pawn.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index e194456e7bc..8e29f89b867 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -20,7 +20,10 @@ public Pawn(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = Math.abs(position.calculateRowGap(targetPosition)); - if (isMovingInitially() && step <= 2) { //초기 움직임 + if (isMovingInitially()) { + if (step > 2) { + throw new IllegalArgumentException("폰은 시작 시 3칸 이상 전진할 수 없습니다."); + } repeatMove(movement, board, step); return; } @@ -48,6 +51,9 @@ private Movement findMovement(Position targetPosition) { private void repeatMove(Movement movement, Board board, int step) { for (int s = 0; s < step; s++) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } Position newPosition = this.position.move(movement); if (board.findByPosition(newPosition).isPresent()) { throw new IllegalArgumentException("장애물이 존재합니다."); From 37d4ba5b5240c23b52e424fb6194e03c8bb4c803 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 15:01:32 +0900 Subject: [PATCH 04/19] =?UTF-8?q?feat=20:=20=ED=82=B9=20=EC=9B=80=EC=A7=81?= =?UTF-8?q?=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/King.java | 79 ++++++++++++++++++++++++- src/main/java/chess/piece/Pawn.java | 9 ++- src/test/java/chess/piece/KingTest.java | 62 +++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/test/java/chess/piece/KingTest.java diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 179ddfcc8f5..26519c3e18f 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -1,11 +1,88 @@ package chess.piece; +import chess.Board; +import chess.Color; +import chess.Movement; import chess.Position; +import java.util.Objects; public class King implements Piece { + private final Color color; + private Position position; + + public King(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void move(Position targetPosition, Board board) { + Movement movement = findMovement(targetPosition); + int step = Math.abs(position.calculateRowGap(targetPosition)); + if (step > 1) { + throw new IllegalArgumentException("킹은 1칸 이상 전진할 수 없습니다."); + } + repeatMove(movement, board, step); + } + + private Movement findMovement(Position targetPosition) { + int columnGap = position.calculateColumnGap(targetPosition); + int rowGap = position.calculateRowGap(targetPosition); + if (rowGap == 0) { + if (position.calculateColumnGap(targetPosition) > 0) { + return Movement.LEFT; + } + return Movement.RIGHT; + } + if (columnGap == 0) { + if (position.calculateRowGap(targetPosition) > 0) { + return Movement.UP; + } + return Movement.DOWN; + } + if (rowGap > 0) { + if (columnGap > 0) { + return Movement.LEFT_UP; + } + return Movement.RIGHT_UP; + } + if (columnGap > 0) { + return Movement.LEFT_DOWN; + } + return Movement.RIGHT_DOWN; + } + + private void repeatMove(Movement movement, Board board, int step) { + for (int s = 0; s < step; s++) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + } + @Override public boolean isPositionEquals(Position targetPosition) { - return false; + return this.position.equals(targetPosition); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + King king = (King) o; + return color == king.color && Objects.equals(position, king.position); + } + + @Override + public int hashCode() { + return Objects.hash(color, position); + } } diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 8e29f89b867..355941da2ae 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -19,7 +19,7 @@ public Pawn(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step = Math.abs(position.calculateRowGap(targetPosition)); + int step =calculateStep(targetPosition); if (isMovingInitially()) { if (step > 2) { throw new IllegalArgumentException("폰은 시작 시 3칸 이상 전진할 수 없습니다."); @@ -33,6 +33,13 @@ public void move(Position targetPosition, Board board) { repeatMove(movement, board, step); } + private int calculateStep(Position targetPosition) { + if (position.isRowEquals(targetPosition)) { + return Math.abs(position.calculateColumnGap(targetPosition)); + } + return Math.abs(position.calculateRowGap(targetPosition)); + } + private Movement findMovement(Position targetPosition) { if (position.isRowEquals(targetPosition)) { if (position.calculateColumnGap(targetPosition) > 0) { diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java new file mode 100644 index 00000000000..b77ffb48db6 --- /dev/null +++ b/src/test/java/chess/piece/KingTest.java @@ -0,0 +1,62 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.List; +import org.junit.jupiter.api.Test; + +class KingTest { + @Test + void moveUpOnce() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + + king.move(new Position(Column.E, Row.SIX), board); + + assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.E, Row.SIX))); + } + + @Test + void moveLeftUpOnce() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + + king.move(new Position(Column.D, Row.SIX), board); + + assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.D, Row.SIX))); + } + + @Test + void moveRightDownOnce() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + + king.move(new Position(Column.F, Row.FOUR), board); + + assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.F, Row.FOUR))); + } + + @Test + void failToMoveTwice() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + + assertThatThrownBy(() -> king.move(new Position(Column.E, Row.THREE), board)) + .isInstanceOf(IllegalArgumentException.class); + } + +} From 733a94b1859c3c1a17ad774723f60b0570a27b35 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 15:06:18 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat=20:=20=ED=80=B8=20=EC=9B=80=EC=A7=81?= =?UTF-8?q?=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Queen.java | 77 +++++++++++++++++++++++- src/test/java/chess/piece/QueenTest.java | 41 +++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/test/java/chess/piece/QueenTest.java diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 909de1ad5f9..6e6cb1f6007 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -1,10 +1,85 @@ package chess.piece; +import chess.Board; +import chess.Color; +import chess.Movement; import chess.Position; +import java.util.Objects; public class Queen implements Piece { + private final Color color; + private Position position; + + public Queen(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void move(Position targetPosition, Board board) { + Movement movement = findMovement(targetPosition); + int step = Math.abs(position.calculateRowGap(targetPosition)); + repeatMove(movement, board, step); + } + + private Movement findMovement(Position targetPosition) { + int columnGap = position.calculateColumnGap(targetPosition); + int rowGap = position.calculateRowGap(targetPosition); + if (rowGap == 0) { + if (position.calculateColumnGap(targetPosition) > 0) { + return Movement.LEFT; + } + return Movement.RIGHT; + } + if (columnGap == 0) { + if (position.calculateRowGap(targetPosition) > 0) { + return Movement.UP; + } + return Movement.DOWN; + } + if (rowGap > 0) { + if (columnGap > 0) { + return Movement.LEFT_UP; + } + return Movement.RIGHT_UP; + } + if (columnGap > 0) { + return Movement.LEFT_DOWN; + } + return Movement.RIGHT_DOWN; + } + + private void repeatMove(Movement movement, Board board, int step) { + for (int s = 0; s < step; s++) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + } + @Override public boolean isPositionEquals(Position targetPosition) { - return false; + return this.position.equals(targetPosition); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Queen queen = (Queen) o; + return color == queen.color && Objects.equals(position, queen.position); + } + + @Override + public int hashCode() { + return Objects.hash(color, position); } } diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java new file mode 100644 index 00000000000..b25194cee4f --- /dev/null +++ b/src/test/java/chess/piece/QueenTest.java @@ -0,0 +1,41 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.List; +import org.junit.jupiter.api.Test; + +class QueenTest { + @Test + void moveUpTwice() { + Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + queen + )); + Position newPosition = new Position(Column.E, Row.SEVEN); + + queen.move(newPosition, board); + + assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); + } + + @Test + void failIfHurdleExists() { + Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + new Pawn(Color.BLACK, new Position(Column.E, Row.SIX)), + queen + )); + Position newPosition = new Position(Column.E, Row.SEVEN); + + assertThatThrownBy(() -> queen.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } + +} From dab459649cd6455c1c984f441a3b1dc4e61ce453 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 15:11:28 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat=20:=20=EB=A3=A9=20=EC=9B=80=EC=A7=81?= =?UTF-8?q?=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Pawn.java | 7 ++- src/main/java/chess/piece/Rook.java | 68 +++++++++++++++++++++++- src/test/java/chess/piece/QueenTest.java | 13 +++++ src/test/java/chess/piece/RookTest.java | 53 ++++++++++++++++++ 4 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 src/test/java/chess/piece/RookTest.java diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 355941da2ae..9c19fe44581 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -41,13 +41,16 @@ private int calculateStep(Position targetPosition) { } private Movement findMovement(Position targetPosition) { - if (position.isRowEquals(targetPosition)) { + //TODO 앞으로만 갈수 있음 + int columnGap = position.calculateColumnGap(targetPosition); + int rowGap = position.calculateRowGap(targetPosition); + if (rowGap == 0) { if (position.calculateColumnGap(targetPosition) > 0) { return Movement.LEFT; } return Movement.RIGHT; } - if (position.isColumnEquals(targetPosition)) { + if (columnGap == 0) { if (position.calculateRowGap(targetPosition) > 0) { return Movement.UP; } diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index a55148941c5..8559b9d4fe5 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -1,11 +1,77 @@ package chess.piece; +import chess.Board; +import chess.Color; +import chess.Movement; import chess.Position; +import java.util.Objects; public class Rook implements Piece { + private final Color color; + private Position position; + + public Rook(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void move(Position targetPosition, Board board) { + Movement movement = findMovement(targetPosition); + int step = Math.abs(position.calculateRowGap(targetPosition)); + repeatMove(movement, board, step); + } + + private Movement findMovement(Position targetPosition) { + int columnGap = position.calculateColumnGap(targetPosition); + int rowGap = position.calculateRowGap(targetPosition); + if (rowGap == 0) { + if (position.calculateColumnGap(targetPosition) > 0) { + return Movement.LEFT; + } + return Movement.RIGHT; + } + if (columnGap == 0) { + if (position.calculateRowGap(targetPosition) > 0) { + return Movement.UP; + } + return Movement.DOWN; + } + throw new IllegalArgumentException("룩은 동서남북 방향으로만 이동 가능합니다."); + } + + private void repeatMove(Movement movement, Board board, int step) { + for (int s = 0; s < step; s++) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + } + @Override public boolean isPositionEquals(Position targetPosition) { - return false; + return this.position.equals(targetPosition); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Rook rook = (Rook) o; + return color == rook.color && Objects.equals(position, rook.position); + } + + @Override + public int hashCode() { + return Objects.hash(color, position); } } diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java index b25194cee4f..c92d9b56c89 100644 --- a/src/test/java/chess/piece/QueenTest.java +++ b/src/test/java/chess/piece/QueenTest.java @@ -25,6 +25,19 @@ void moveUpTwice() { assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); } + @Test + void moveLeftUpTwice() { + Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + queen + )); + Position newPosition = new Position(Column.C, Row.SEVEN); + + queen.move(newPosition, board); + + assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); + } + @Test void failIfHurdleExists() { Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); diff --git a/src/test/java/chess/piece/RookTest.java b/src/test/java/chess/piece/RookTest.java new file mode 100644 index 00000000000..426a5d40d31 --- /dev/null +++ b/src/test/java/chess/piece/RookTest.java @@ -0,0 +1,53 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RookTest { + @Test + void moveUpTwice() { + Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + rook + )); + Position newPosition = new Position(Column.E, Row.SEVEN); + + rook.move(newPosition, board); + + assertThat(rook).isEqualTo(new Rook(Color.WHITE, newPosition)); + } + + @Test + void failIfDiagonalMove() { + Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + rook + )); + Position newPosition = new Position(Column.D, Row.FOUR); + + assertThatThrownBy(() -> rook.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void failIfHurdleExists() { + Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + new Pawn(Color.BLACK, new Position(Column.E, Row.SIX)), + rook + )); + Position newPosition = new Position(Column.E, Row.SEVEN); + + assertThatThrownBy(() -> rook.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } + +} From 6e95025e4488194ad8b495ca46e59a8663e4d4fb Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 15:18:51 +0900 Subject: [PATCH 07/19] =?UTF-8?q?feat=20:=20=EB=B9=84=EC=88=8D=20=EC=9B=80?= =?UTF-8?q?=EC=A7=81=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Bishop.java | 68 ++++++++++++++++++++++- src/test/java/chess/piece/BishopTest.java | 53 ++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/test/java/chess/piece/BishopTest.java diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 981be8d0502..8781e18de76 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -1,10 +1,76 @@ package chess.piece; +import chess.Board; +import chess.Color; +import chess.Movement; import chess.Position; +import java.util.Objects; public class Bishop implements Piece{ + private final Color color; + private Position position; + + public Bishop(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void move(Position targetPosition, Board board) { + Movement movement = findMovement(targetPosition); + int step = Math.abs(position.calculateRowGap(targetPosition)); + repeatMove(movement, board, step); + } + + private Movement findMovement(Position targetPosition) { + int columnGap = position.calculateColumnGap(targetPosition); + int rowGap = position.calculateRowGap(targetPosition); + if (rowGap > 0) { + if (columnGap > 0) { + return Movement.LEFT_UP; + } + return Movement.RIGHT_UP; + } + if (rowGap < 0) { + if (columnGap > 0) { + return Movement.LEFT_DOWN; + } + return Movement.RIGHT_DOWN; + } + throw new IllegalArgumentException("비숍은 대각선 방향으로만 이동 가능합니다."); + } + + private void repeatMove(Movement movement, Board board, int step) { + for (int s = 0; s < step; s++) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + } + @Override public boolean isPositionEquals(Position targetPosition) { - return false; + return this.position.equals(targetPosition); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Bishop bishop = (Bishop) o; + return color == bishop.color && Objects.equals(position, bishop.position); + } + + @Override + public int hashCode() { + return Objects.hash(color, position); } } diff --git a/src/test/java/chess/piece/BishopTest.java b/src/test/java/chess/piece/BishopTest.java new file mode 100644 index 00000000000..950a96a3ca6 --- /dev/null +++ b/src/test/java/chess/piece/BishopTest.java @@ -0,0 +1,53 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.List; +import org.junit.jupiter.api.Test; + +class BishopTest { + + @Test + void moveLeftUpTwice() { + Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + bishop + )); + Position newPosition = new Position(Column.C, Row.SEVEN); + + bishop.move(newPosition, board); + + assertThat(bishop).isEqualTo(new Bishop(Color.WHITE, newPosition)); + } + + @Test + void failIfCardinalMove() { + Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + bishop + )); + Position newPosition = new Position(Column.C, Row.FIVE); + + assertThatThrownBy(() -> bishop.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void failIfHurdleExists() { + Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + new Pawn(Color.BLACK, new Position(Column.D, Row.SIX)), + bishop + )); + Position newPosition = new Position(Column.C, Row.SEVEN); + + assertThatThrownBy(() -> bishop.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } +} From 92de8bfbe4ddfec3b872eda8f4fea2edc5ea6ca6 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 15:43:20 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat=20:=20=EB=82=98=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=9B=80=EC=A7=81=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Bishop.java | 8 +- src/main/java/chess/piece/King.java | 4 +- src/main/java/chess/piece/Knight.java | 89 ++++++++++++++++++++++- src/main/java/chess/piece/Queen.java | 2 +- src/test/java/chess/piece/KingTest.java | 1 - src/test/java/chess/piece/KnightTest.java | 53 ++++++++++++++ 6 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/test/java/chess/piece/KnightTest.java diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 8781e18de76..858985901a9 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -28,13 +28,17 @@ private Movement findMovement(Position targetPosition) { if (columnGap > 0) { return Movement.LEFT_UP; } - return Movement.RIGHT_UP; + if (columnGap < 0) { + return Movement.RIGHT_UP; + } } if (rowGap < 0) { if (columnGap > 0) { return Movement.LEFT_DOWN; } - return Movement.RIGHT_DOWN; + if (columnGap < 0) { + return Movement.RIGHT_DOWN; + } } throw new IllegalArgumentException("비숍은 대각선 방향으로만 이동 가능합니다."); } diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 26519c3e18f..df1d025126a 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -28,13 +28,13 @@ private Movement findMovement(Position targetPosition) { int columnGap = position.calculateColumnGap(targetPosition); int rowGap = position.calculateRowGap(targetPosition); if (rowGap == 0) { - if (position.calculateColumnGap(targetPosition) > 0) { + if (columnGap > 0) { return Movement.LEFT; } return Movement.RIGHT; } if (columnGap == 0) { - if (position.calculateRowGap(targetPosition) > 0) { + if (rowGap > 0) { return Movement.UP; } return Movement.DOWN; diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index b4eff364c9a..5b3ed71a19d 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -1,11 +1,98 @@ package chess.piece; +import chess.Board; +import chess.Color; +import chess.Movement; import chess.Position; +import java.util.List; +import java.util.Objects; public class Knight implements Piece { + private final Color color; + private Position position; + + public Knight(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void move(Position targetPosition, Board board) { + List movements = findMovement(targetPosition); + repeatMove(movements, board); + } + + private List findMovement(Position targetPosition) { + int columnGap = position.calculateColumnGap(targetPosition); + int rowGap = position.calculateRowGap(targetPosition); + Movement firstMovement = decideFirstMovement(rowGap, columnGap); + Movement secondMovement = decideSecondMovement(rowGap, columnGap); + return List.of(firstMovement, firstMovement, secondMovement); + } + + private void repeatMove(List movements, Board board) { + for (Movement movement : movements) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + } + + private static Movement decideFirstMovement(int rowGap, int columnGap) { + if (rowGap == 2) { + return Movement.UP; + } + if (rowGap == -2) { + return Movement.DOWN; + } + if (columnGap == 2) { + return Movement.LEFT; + } + if (columnGap == -2) { + return Movement.RIGHT; + } + throw new IllegalArgumentException("나이트는 L자모양 이동만 가능합니다."); + } + + private static Movement decideSecondMovement(int rowGap, int columnGap) { + if (rowGap == 1) { + return Movement.UP; + } + if (rowGap == -1) { + return Movement.DOWN; + } + if (columnGap == 1) { + return Movement.LEFT; + } + if (columnGap == -1) { + return Movement.RIGHT; + } + throw new IllegalArgumentException("나이트는 L자모양 이동만 가능합니다."); + } + @Override public boolean isPositionEquals(Position targetPosition) { - return false; + return this.position.equals(targetPosition); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Knight knight = (Knight) o; + return color == knight.color && Objects.equals(position, knight.position); + } + + @Override + public int hashCode() { + return Objects.hash(color, position); + } } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 6e6cb1f6007..a5a4fe668bb 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -17,7 +17,7 @@ public Queen(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step = Math.abs(position.calculateRowGap(targetPosition)); + int step = Math.abs(position.calculateRowGap(targetPosition)); //TODO 수정 repeatMove(movement, board, step); } diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java index b77ffb48db6..1d0df1fe6c3 100644 --- a/src/test/java/chess/piece/KingTest.java +++ b/src/test/java/chess/piece/KingTest.java @@ -58,5 +58,4 @@ void failToMoveTwice() { assertThatThrownBy(() -> king.move(new Position(Column.E, Row.THREE), board)) .isInstanceOf(IllegalArgumentException.class); } - } diff --git a/src/test/java/chess/piece/KnightTest.java b/src/test/java/chess/piece/KnightTest.java new file mode 100644 index 00000000000..5825af64e5a --- /dev/null +++ b/src/test/java/chess/piece/KnightTest.java @@ -0,0 +1,53 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.List; +import org.junit.jupiter.api.Test; + +class KnightTest { + @Test + void moveUpUpLeftOnce() { + Knight knight = new Knight(Color.WHITE, new Position(Column.D, Row.FIVE)); + Board board = new Board(List.of( + knight + )); + Position newPosition = new Position(Column.C, Row.SEVEN); + + knight.move(newPosition, board); + + assertThat(knight).isEqualTo(new Knight(Color.WHITE, newPosition)); + } + + @Test + void moveRightRightDownOnce() { + Knight knight = new Knight(Color.WHITE, new Position(Column.D, Row.FIVE)); + Board board = new Board(List.of( + knight + )); + Position newPosition = new Position(Column.F, Row.FOUR); + + + knight.move(newPosition, board); + + assertThat(knight).isEqualTo(new Knight(Color.WHITE, newPosition)); + } + + @Test + void failToMoveOther() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + Position newPosition = new Position(Column.F, Row.THREE); + + assertThatThrownBy(() -> king.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } +} From 0dbc1f806611e7317be1f90f2e98ffe63c680f9b Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 16:13:50 +0900 Subject: [PATCH 09/19] =?UTF-8?q?feat=20:=20=EB=82=98=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=A0=9C=EC=99=B8=20=EC=9D=BC=EC=A7=81=EC=84=A0=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Bishop.java | 13 ++++++++- src/main/java/chess/piece/King.java | 35 ++++++++++++++--------- src/main/java/chess/piece/Pawn.java | 8 +++--- src/main/java/chess/piece/Queen.java | 19 +++++++++++- src/main/java/chess/piece/Rook.java | 9 +++++- src/test/java/chess/piece/BishopTest.java | 12 ++++++++ src/test/java/chess/piece/KingTest.java | 24 ++++++++++++++++ src/test/java/chess/piece/QueenTest.java | 24 ++++++++++++++++ src/test/java/chess/piece/RookTest.java | 24 ++++++++++++++++ 9 files changed, 147 insertions(+), 21 deletions(-) diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 858985901a9..781c34f4740 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -17,13 +17,14 @@ public Bishop(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step = Math.abs(position.calculateRowGap(targetPosition)); + int step = calculateStep(targetPosition); repeatMove(movement, board, step); } private Movement findMovement(Position targetPosition) { int columnGap = position.calculateColumnGap(targetPosition); int rowGap = position.calculateRowGap(targetPosition); + validateStraightMove(rowGap, columnGap); if (rowGap > 0) { if (columnGap > 0) { return Movement.LEFT_UP; @@ -43,6 +44,16 @@ private Movement findMovement(Position targetPosition) { throw new IllegalArgumentException("비숍은 대각선 방향으로만 이동 가능합니다."); } + private void validateStraightMove(int rowGap, int columnGap) { + if (Math.abs(rowGap) != Math.abs(columnGap)) { + throw new IllegalArgumentException("비숍은 한 방향으로만 이동 가능합니다."); + } + } + + private int calculateStep(Position targetPosition) { + return Math.abs(position.calculateRowGap(targetPosition)); + } + private void repeatMove(Movement movement, Board board, int step) { for (int s = 0; s < step; s++) { if (!this.position.canMove(movement)) { diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index df1d025126a..1848b70d23e 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -17,11 +17,11 @@ public King(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step = Math.abs(position.calculateRowGap(targetPosition)); - if (step > 1) { - throw new IllegalArgumentException("킹은 1칸 이상 전진할 수 없습니다."); + int step = calculateStep(targetPosition); + if (step != 1) { + throw new IllegalArgumentException("킹은 1칸만 전진할 수 있습니다."); } - repeatMove(movement, board, step); + repeatMove(movement, board); } private Movement findMovement(Position targetPosition) { @@ -51,17 +51,24 @@ private Movement findMovement(Position targetPosition) { return Movement.RIGHT_DOWN; } - private void repeatMove(Movement movement, Board board, int step) { - for (int s = 0; s < step; s++) { - if (!this.position.canMove(movement)) { - throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); - } - Position newPosition = this.position.move(movement); - if (board.findByPosition(newPosition).isPresent()) { - throw new IllegalArgumentException("장애물이 존재합니다."); - } - this.position = newPosition; + private int calculateStep(Position targetPosition) { + int rowGap = position.calculateRowGap(targetPosition); + int columnGap = position.calculateColumnGap(targetPosition); + if (rowGap == 0) { + return Math.abs(columnGap); + } + return Math.abs(rowGap); + } + + private void repeatMove(Movement movement, Board board) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); } + this.position = newPosition; } @Override diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 9c19fe44581..e5acc925ed3 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -21,14 +21,14 @@ public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step =calculateStep(targetPosition); if (isMovingInitially()) { - if (step > 2) { - throw new IllegalArgumentException("폰은 시작 시 3칸 이상 전진할 수 없습니다."); + if (step > 2 || step == 0) { + throw new IllegalArgumentException("폰은 시작 시 1칸 또는 2칸만 전진할 수 있습니다."); } repeatMove(movement, board, step); return; } - if (step >= 2) { - throw new IllegalArgumentException("폰은 2칸 이상 전진할 수 없습니다."); + if (step >= 2 || step == 0) { + throw new IllegalArgumentException("폰은 1칸만 전진할 수 없습니다."); } repeatMove(movement, board, step); } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index a5a4fe668bb..f8722b55798 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -17,13 +17,14 @@ public Queen(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step = Math.abs(position.calculateRowGap(targetPosition)); //TODO 수정 + int step = calculateStep(targetPosition); repeatMove(movement, board, step); } private Movement findMovement(Position targetPosition) { int columnGap = position.calculateColumnGap(targetPosition); int rowGap = position.calculateRowGap(targetPosition); + validateStraightMove(rowGap, columnGap); if (rowGap == 0) { if (position.calculateColumnGap(targetPosition) > 0) { return Movement.LEFT; @@ -48,6 +49,22 @@ private Movement findMovement(Position targetPosition) { return Movement.RIGHT_DOWN; } + private void validateStraightMove(int rowGap, int columnGap) { + if (rowGap == 0 || columnGap == 0 || Math.abs(rowGap) == Math.abs(columnGap)) { + return; + } + throw new IllegalArgumentException("퀸은 한 방향으로만 움직일 수 있습니다."); + } + + private int calculateStep(Position targetPosition) { + int rowGap = position.calculateRowGap(targetPosition); + int columnGap = position.calculateColumnGap(targetPosition); + if (rowGap == 0) { + return Math.abs(columnGap); + } + return Math.abs(rowGap); + } + private void repeatMove(Movement movement, Board board, int step) { for (int s = 0; s < step; s++) { if (!this.position.canMove(movement)) { diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 8559b9d4fe5..c892ce0b54e 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -17,10 +17,17 @@ public Rook(Color color, Position position) { public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step = Math.abs(position.calculateRowGap(targetPosition)); + int step = calculateStep(targetPosition); repeatMove(movement, board, step); } + private int calculateStep(Position targetPosition) { + if (position.isRowEquals(targetPosition)) { + return Math.abs(position.calculateColumnGap(targetPosition)); + } + return Math.abs(position.calculateRowGap(targetPosition)); + } + private Movement findMovement(Position targetPosition) { int columnGap = position.calculateColumnGap(targetPosition); int rowGap = position.calculateRowGap(targetPosition); diff --git a/src/test/java/chess/piece/BishopTest.java b/src/test/java/chess/piece/BishopTest.java index 950a96a3ca6..bf8a67c7228 100644 --- a/src/test/java/chess/piece/BishopTest.java +++ b/src/test/java/chess/piece/BishopTest.java @@ -38,6 +38,18 @@ void failIfCardinalMove() { .isInstanceOf(IllegalArgumentException.class); } + @Test + void failIfNotStraight() { + Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + bishop + )); + Position newPosition = new Position(Column.G, Row.SIX); + + assertThatThrownBy(() -> bishop.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } + @Test void failIfHurdleExists() { Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java index 1d0df1fe6c3..79de067156c 100644 --- a/src/test/java/chess/piece/KingTest.java +++ b/src/test/java/chess/piece/KingTest.java @@ -24,6 +24,19 @@ void moveUpOnce() { assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.E, Row.SIX))); } + @Test + void moveRightOnce() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + Position newPosition = new Position(Column.F, Row.FIVE); + + king.move(newPosition, board); + + assertThat(king).isEqualTo(new King(Color.WHITE, newPosition)); + } + @Test void moveLeftUpOnce() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); @@ -58,4 +71,15 @@ void failToMoveTwice() { assertThatThrownBy(() -> king.move(new Position(Column.E, Row.THREE), board)) .isInstanceOf(IllegalArgumentException.class); } + + @Test + void failIfNotStraight() { + King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + king + )); + + assertThatThrownBy(() -> king.move(new Position(Column.D, Row.THREE), board)) + .isInstanceOf(IllegalArgumentException.class); + } } diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java index c92d9b56c89..0f67a31f2b8 100644 --- a/src/test/java/chess/piece/QueenTest.java +++ b/src/test/java/chess/piece/QueenTest.java @@ -25,6 +25,19 @@ void moveUpTwice() { assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); } + @Test + void moveRightTwice() { + Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + queen + )); + Position newPosition = new Position(Column.G, Row.FIVE); + + queen.move(newPosition, board); + + assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); + } + @Test void moveLeftUpTwice() { Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); @@ -51,4 +64,15 @@ void failIfHurdleExists() { .isInstanceOf(IllegalArgumentException.class); } + @Test + void failIfNotStraight() { + Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + queen + )); + Position newPosition = new Position(Column.F, Row.SEVEN); + + assertThatThrownBy(() -> queen.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } } diff --git a/src/test/java/chess/piece/RookTest.java b/src/test/java/chess/piece/RookTest.java index 426a5d40d31..f93cc1bd6ff 100644 --- a/src/test/java/chess/piece/RookTest.java +++ b/src/test/java/chess/piece/RookTest.java @@ -25,6 +25,19 @@ void moveUpTwice() { assertThat(rook).isEqualTo(new Rook(Color.WHITE, newPosition)); } + @Test + void moveRightTwice() { + Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + rook + )); + Position newPosition = new Position(Column.G, Row.FIVE); + + rook.move(newPosition, board); + + assertThat(rook).isEqualTo(new Rook(Color.WHITE, newPosition)); + } + @Test void failIfDiagonalMove() { Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); @@ -50,4 +63,15 @@ void failIfHurdleExists() { .isInstanceOf(IllegalArgumentException.class); } + @Test + void failIfNotStraight() { + Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); + Board board = new Board(List.of( + rook + )); + Position newPosition = new Position(Column.F, Row.SEVEN); + + assertThatThrownBy(() -> rook.move(newPosition, board)) + .isInstanceOf(IllegalArgumentException.class); + } } From 4001eaf989ffdc054bac9ae05fcf8936c3e2fd59 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 16:21:06 +0900 Subject: [PATCH 10/19] =?UTF-8?q?feat=20:=20=EC=9E=A5=EC=95=A0=EB=AC=BC?= =?UTF-8?q?=EC=9D=84=20=EC=8A=A4=EC=8A=A4=EB=A1=9C=20=ED=8C=90=EB=8B=A8?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Board.java | 9 ++++++++- src/main/java/chess/Hurdles.java | 19 +++++++++++++++++++ src/main/java/chess/piece/Bishop.java | 4 ++-- src/main/java/chess/piece/King.java | 4 ++-- src/main/java/chess/piece/Knight.java | 4 ++-- src/main/java/chess/piece/Pawn.java | 5 ++--- src/main/java/chess/piece/Piece.java | 3 ++- src/main/java/chess/piece/Queen.java | 4 ++-- src/main/java/chess/piece/Rook.java | 4 ++-- 9 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 src/main/java/chess/Hurdles.java diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java index 4d78366f01a..b34b71673e4 100644 --- a/src/main/java/chess/Board.java +++ b/src/main/java/chess/Board.java @@ -11,10 +11,17 @@ public Board(List pieces) { this.pieces = pieces; } + //TODO 존재하는 포지션만 주기 + + public Hurdles findHurdlePositions() { + return new Hurdles(pieces.stream() + .map(Piece::getPosition) + .toList()); + } public Optional findByPosition(Position newPosition) { return pieces.stream() - .filter(piece -> piece.isPositionEquals(newPosition)) + .filter(piece -> piece.getPosition().equals(newPosition)) //TODO 수정 .findFirst(); } } diff --git a/src/main/java/chess/Hurdles.java b/src/main/java/chess/Hurdles.java new file mode 100644 index 00000000000..1f94a9241c0 --- /dev/null +++ b/src/main/java/chess/Hurdles.java @@ -0,0 +1,19 @@ +package chess; + +import java.util.List; + +public class Hurdles { + + //TODO 가능하면 교체 + private final List positions; + + public Hurdles(List positions) { + this.positions = positions; + } + + public void checkCrash(Position position) { + if (positions.contains(position)) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + } +} diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 781c34f4740..1dd178116c5 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -68,8 +68,8 @@ private void repeatMove(Movement movement, Board board, int step) { } @Override - public boolean isPositionEquals(Position targetPosition) { - return this.position.equals(targetPosition); + public Position getPosition() { + return this.position; } @Override diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 1848b70d23e..e8692acce29 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -72,8 +72,8 @@ private void repeatMove(Movement movement, Board board) { } @Override - public boolean isPositionEquals(Position targetPosition) { - return this.position.equals(targetPosition); + public Position getPosition() { + return this.position; } @Override diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 5b3ed71a19d..e487d15b9e5 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -75,8 +75,8 @@ private static Movement decideSecondMovement(int rowGap, int columnGap) { } @Override - public boolean isPositionEquals(Position targetPosition) { - return this.position.equals(targetPosition); + public Position getPosition() { + return this.position; } @Override diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index e5acc925ed3..60eb7bc1e23 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -80,11 +80,10 @@ private boolean isMovingInitially() { } @Override - public boolean isPositionEquals(Position targetPosition) { - return this.position.equals(targetPosition); + public Position getPosition() { + return this.position; } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java index fb00a4c19fb..5cb6a17cf60 100644 --- a/src/main/java/chess/piece/Piece.java +++ b/src/main/java/chess/piece/Piece.java @@ -3,5 +3,6 @@ import chess.Position; public interface Piece { - boolean isPositionEquals(Position targetPosition); + + Position getPosition(); } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index f8722b55798..202f660e448 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -79,8 +79,8 @@ private void repeatMove(Movement movement, Board board, int step) { } @Override - public boolean isPositionEquals(Position targetPosition) { - return this.position.equals(targetPosition); + public Position getPosition() { + return this.position; } @Override diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index c892ce0b54e..4a8c1b6ad4d 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -60,8 +60,8 @@ private void repeatMove(Movement movement, Board board, int step) { } @Override - public boolean isPositionEquals(Position targetPosition) { - return this.position.equals(targetPosition); + public Position getPosition() { + return this.position; } @Override From a9795e94f6240a91c71f3ef66ecd9ec1fda023c4 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 17:08:42 +0900 Subject: [PATCH 11/19] =?UTF-8?q?feat=20:=20=EA=B8=B0=EB=AC=BC=EC=9D=98=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EC=B4=88=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Board.java | 21 +++++++++++++++++++++ src/main/java/chess/Color.java | 25 ++++++++++++++++++++++--- src/main/java/chess/Position.java | 4 ++++ src/main/java/chess/Row.java | 9 +++++++++ src/main/java/chess/piece/Bishop.java | 14 ++++++++++++++ src/main/java/chess/piece/King.java | 11 +++++++++++ src/main/java/chess/piece/Knight.java | 13 +++++++++++++ src/main/java/chess/piece/Pawn.java | 14 ++++++++++++++ src/main/java/chess/piece/Piece.java | 1 - src/main/java/chess/piece/Queen.java | 10 ++++++++++ src/main/java/chess/piece/Rook.java | 14 ++++++++++++++ 11 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java index b34b71673e4..3737bbfe3f3 100644 --- a/src/main/java/chess/Board.java +++ b/src/main/java/chess/Board.java @@ -1,6 +1,13 @@ package chess; +import chess.piece.Bishop; +import chess.piece.King; +import chess.piece.Knight; +import chess.piece.Pawn; import chess.piece.Piece; +import chess.piece.Queen; +import chess.piece.Rook; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -11,6 +18,20 @@ public Board(List pieces) { this.pieces = pieces; } + public static Board initialize() { + List pieces = new ArrayList<>(); + + for (Color color : Color.validColors()) { + pieces.addAll(Bishop.initialize(color)); + pieces.addAll(King.initialize(color)); + pieces.addAll(Knight.initialize(color)); + pieces.addAll(Pawn.initialize(color)); + pieces.addAll(Queen.initialize(color)); + pieces.addAll(Rook.initialize(color)); + } + return new Board(pieces); + } + //TODO 존재하는 포지션만 주기 public Hurdles findHurdlePositions() { diff --git a/src/main/java/chess/Color.java b/src/main/java/chess/Color.java index 55cd020b681..345e4f26a85 100644 --- a/src/main/java/chess/Color.java +++ b/src/main/java/chess/Color.java @@ -1,10 +1,25 @@ package chess; +import java.util.Arrays; +import java.util.List; + public enum Color { - BLACK, - WHITE, - EMPTY; + BLACK(new Position(Column.A, Row.SEVEN)), + WHITE(new Position(Column.A, Row.ONE)), + EMPTY(null); + + private final Position firstPawnPosition; + + Color(Position firstPawnPosition) { + this.firstPawnPosition = firstPawnPosition; + } + + public static List validColors() { + return Arrays.stream(Color.values()) + .filter(color -> !color.isEmpty()) + .toList(); + } public boolean isWhite() { return this == WHITE; @@ -25,4 +40,8 @@ public Color opposite() { default -> EMPTY; }; } + + public Position getFirstPawnPosition() { + return firstPawnPosition; + } } diff --git a/src/main/java/chess/Position.java b/src/main/java/chess/Position.java index 4d0c1efa9e8..158d4e69e04 100644 --- a/src/main/java/chess/Position.java +++ b/src/main/java/chess/Position.java @@ -148,6 +148,10 @@ public Position move(final Movement movement) { return moveVertical(movement.y()).moveHorizontal(movement.x()); } + public Position move(final int x, final int y) { + return moveVertical(x).moveHorizontal(y); + } + public Position moveVertical(final int step) { if (step > 0) { return moveUp(step); diff --git a/src/main/java/chess/Row.java b/src/main/java/chess/Row.java index 60f63fa3567..1afa248bf73 100644 --- a/src/main/java/chess/Row.java +++ b/src/main/java/chess/Row.java @@ -1,5 +1,7 @@ package chess; +import java.util.Arrays; + public enum Row { EIGHT, // 0 @@ -11,6 +13,13 @@ public enum Row { TWO, ONE; + public static Row fromNumber(int number) { + return Arrays.stream(Row.values()) + .filter(row -> row.ordinal() == 8 - number) + .findFirst() + .orElseThrow(IllegalStateException::new); + } + public boolean isTop() { return ordinal() == 0; } diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 1dd178116c5..b57c9d68ee8 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -2,8 +2,12 @@ import chess.Board; import chess.Color; +import chess.Column; import chess.Movement; import chess.Position; +import chess.Row; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; public class Bishop implements Piece{ @@ -67,6 +71,16 @@ private void repeatMove(Movement movement, Board board, int step) { } } + public static List initialize(Color color) { + Position standard = new Position(Column.C, Row.ONE); + if (color.isBlack()) { + standard = new Position(Column.C, Row.EIGHT); + } + return List.of(new Bishop(color, standard), + new Bishop(color, standard.move(0, 3)) + ); + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index e8692acce29..81f02472de4 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -2,8 +2,12 @@ import chess.Board; import chess.Color; +import chess.Column; import chess.Movement; import chess.Position; +import chess.Row; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; public class King implements Piece { @@ -71,6 +75,13 @@ private void repeatMove(Movement movement, Board board) { this.position = newPosition; } + public static List initialize(Color color) { + if (color.isWhite()) { + return List.of(new King(color, new Position(Column.E, Row.ONE))); + } + return List.of(new King(color, new Position(Column.E, Row.EIGHT))); + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index e487d15b9e5..2866c1d4b72 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -2,8 +2,11 @@ import chess.Board; import chess.Color; +import chess.Column; import chess.Movement; import chess.Position; +import chess.Row; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -74,6 +77,16 @@ private static Movement decideSecondMovement(int rowGap, int columnGap) { throw new IllegalArgumentException("나이트는 L자모양 이동만 가능합니다."); } + public static List initialize(Color color) { + Position standard = new Position(Column.B, Row.ONE); + if (color.isBlack()) { + standard = new Position(Column.B, Row.EIGHT); + } + return List.of(new Knight(color, standard), + new Knight(color, standard.move(0, 5)) + ); + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 60eb7bc1e23..95c563e2150 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -6,6 +6,8 @@ import chess.Movement; import chess.Position; import chess.Row; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; public class Pawn implements Piece { @@ -79,6 +81,18 @@ private boolean isMovingInitially() { return position.isRowEquals(new Position(Column.A, Row.SEVEN)); } + public static List initialize(Color color) { + List pieces = new ArrayList<>(); + Position standardPawnPosition = new Position(Column.A, Row.TWO); + if (color.isBlack()) { + standardPawnPosition = new Position(Column.A, Row.SEVEN); + } + for (int i = 0; i <= 7; i++) { + pieces.add(new Pawn(color, standardPawnPosition.move(0, i))); + } + return pieces; + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java index 5cb6a17cf60..eaab6845b2f 100644 --- a/src/main/java/chess/piece/Piece.java +++ b/src/main/java/chess/piece/Piece.java @@ -3,6 +3,5 @@ import chess.Position; public interface Piece { - Position getPosition(); } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 202f660e448..974ba5d2452 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -2,8 +2,11 @@ import chess.Board; import chess.Color; +import chess.Column; import chess.Movement; import chess.Position; +import chess.Row; +import java.util.List; import java.util.Objects; public class Queen implements Piece { @@ -78,6 +81,13 @@ private void repeatMove(Movement movement, Board board, int step) { } } + public static List initialize(Color color) { + if (color.isWhite()) { + return List.of(new Queen(color, new Position(Column.D, Row.ONE))); + } + return List.of(new Queen(color, new Position(Column.D, Row.EIGHT))); + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 4a8c1b6ad4d..ef977267c6c 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -2,8 +2,12 @@ import chess.Board; import chess.Color; +import chess.Column; import chess.Movement; import chess.Position; +import chess.Row; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; public class Rook implements Piece { @@ -59,6 +63,16 @@ private void repeatMove(Movement movement, Board board, int step) { } } + public static List initialize(Color color) { + Position standard = new Position(Column.A, Row.ONE); + if (color.isBlack()) { + standard = new Position(Column.A, Row.EIGHT); + } + return List.of(new Rook(color, standard), + new Rook(color, standard.move(0, 7)) + ); + } + @Override public Position getPosition() { return this.position; From 85c8d033050430d00ed270b248af2ca7649a59e5 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 18:32:47 +0900 Subject: [PATCH 12/19] =?UTF-8?q?feat=20:=20=EB=B7=B0=EC=99=80=20=EB=B7=B0?= =?UTF-8?q?=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Board.java | 19 +++++-- src/main/java/chess/Column.java | 10 ++++ src/main/java/chess/Position.java | 6 +++ src/main/java/chess/Row.java | 8 +++ .../java/chess/game/ChessApplication.java | 33 ++++++++++++ src/main/java/chess/piece/Bishop.java | 12 ++++- src/main/java/chess/piece/King.java | 12 ++++- src/main/java/chess/piece/Knight.java | 12 ++++- src/main/java/chess/piece/Pawn.java | 11 ++++ src/main/java/chess/piece/Piece.java | 7 +++ src/main/java/chess/piece/Queen.java | 11 ++++ src/main/java/chess/piece/Rook.java | 12 ++++- src/main/java/chess/view/BoardView.java | 53 +++++++++++++++++++ src/main/java/chess/view/InputView.java | 29 ++++++++++ 14 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 src/main/java/chess/game/ChessApplication.java create mode 100644 src/main/java/chess/view/BoardView.java create mode 100644 src/main/java/chess/view/InputView.java diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java index 3737bbfe3f3..61e0f9516f6 100644 --- a/src/main/java/chess/Board.java +++ b/src/main/java/chess/Board.java @@ -8,6 +8,7 @@ import chess.piece.Queen; import chess.piece.Rook; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -33,16 +34,28 @@ public static Board initialize() { } //TODO 존재하는 포지션만 주기 - public Hurdles findHurdlePositions() { return new Hurdles(pieces.stream() .map(Piece::getPosition) .toList()); } - public Optional findByPosition(Position newPosition) { + public Optional findByPosition(Position position) { return pieces.stream() - .filter(piece -> piece.getPosition().equals(newPosition)) //TODO 수정 + .filter(piece -> piece.getPosition().equals(position)) //TODO 수정 .findFirst(); } + + public List getPieces() { + return Collections.unmodifiableList(pieces); + } + + public Piece findByPositionOrThrow(Position position) { + return findByPosition(position) + .orElseThrow(() -> new IllegalArgumentException("해당하는 좌표에 기물이 없습니다.")); + } + + public void move(Piece movingPiece, Position targetPosition) { + movingPiece.move(targetPosition, this); + } } diff --git a/src/main/java/chess/Column.java b/src/main/java/chess/Column.java index b64b4dc77a3..e5055654660 100644 --- a/src/main/java/chess/Column.java +++ b/src/main/java/chess/Column.java @@ -1,5 +1,7 @@ package chess; +import java.util.Arrays; + public enum Column { A, @@ -11,6 +13,14 @@ public enum Column { G, H; + public static String ofOrdinal(int ordinal) { + return Arrays.stream(Column.values()) + .filter(column -> column.ordinal() == ordinal) + .map(Enum::name) + .findFirst() + .orElseThrow(IllegalStateException::new); + } + public boolean isFarLeft() { return ordinal() == 0; } diff --git a/src/main/java/chess/Position.java b/src/main/java/chess/Position.java index 158d4e69e04..86bf8e5a31a 100644 --- a/src/main/java/chess/Position.java +++ b/src/main/java/chess/Position.java @@ -190,5 +190,11 @@ public int calculateColumnGap(Position targetPosition) { return this.column.ordinal() - targetPosition.column.ordinal(); } + public int getRow() { + return row.ordinal(); + } + public int getColumn() { + return column.ordinal(); + } } diff --git a/src/main/java/chess/Row.java b/src/main/java/chess/Row.java index 1afa248bf73..fc14d0271d6 100644 --- a/src/main/java/chess/Row.java +++ b/src/main/java/chess/Row.java @@ -20,6 +20,14 @@ public static Row fromNumber(int number) { .orElseThrow(IllegalStateException::new); } + public static String ofOrdinal(int ordinal) { + return Arrays.stream(Row.values()) + .filter(row -> row.ordinal() == ordinal) + .map(row -> ((8 - row.ordinal()) + "")) + .findFirst() + .orElseThrow(IllegalStateException::new); + } + public boolean isTop() { return ordinal() == 0; } diff --git a/src/main/java/chess/game/ChessApplication.java b/src/main/java/chess/game/ChessApplication.java new file mode 100644 index 00000000000..95c0fcf7c04 --- /dev/null +++ b/src/main/java/chess/game/ChessApplication.java @@ -0,0 +1,33 @@ +package chess.game; + +import chess.Board; +import chess.Color; +import chess.Position; +import chess.piece.Piece; +import chess.view.BoardView; +import chess.view.InputView; + +public class ChessApplication { + public static void main(String[] args) { + ChessApplication chessApplication = new ChessApplication(); + + chessApplication.start(); + } + + private void start() { + Board board = Board.initialize(); + + Color color = Color.WHITE; + while (true) { //TODO 승패 조건 추가 + BoardView.printBoard(board); + + Position movingPosition = InputView.readMovingPosition(); + Piece movingPiece = board.findByPositionOrThrow(movingPosition); + Position targetPosition = InputView.readTargetPosition(); + + board.move(movingPiece, targetPosition); + + color = color.opposite(); + } + } +} diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index b57c9d68ee8..09f607fa4ef 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -6,7 +6,6 @@ import chess.Movement; import chess.Position; import chess.Row; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -19,6 +18,7 @@ public Bishop(Color color, Position position) { this.position = position; } + @Override public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); @@ -81,11 +81,21 @@ public static List initialize(Color color) { ); } + @Override + public boolean isBlack() { + return this.color.isBlack(); + } + @Override public Position getPosition() { return this.position; } + @Override + public String getName() { + return "비"; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 81f02472de4..4f66a406788 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -6,7 +6,6 @@ import chess.Movement; import chess.Position; import chess.Row; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -19,6 +18,7 @@ public King(Color color, Position position) { this.position = position; } + @Override public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); @@ -82,6 +82,16 @@ public static List initialize(Color color) { return List.of(new King(color, new Position(Column.E, Row.EIGHT))); } + @Override + public boolean isBlack() { + return this.color.isBlack(); + } + + @Override + public String getName() { + return "킹"; + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 2866c1d4b72..bf71984dccf 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -6,7 +6,6 @@ import chess.Movement; import chess.Position; import chess.Row; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -19,6 +18,7 @@ public Knight(Color color, Position position) { this.position = position; } + @Override public void move(Position targetPosition, Board board) { List movements = findMovement(targetPosition); repeatMove(movements, board); @@ -87,6 +87,16 @@ public static List initialize(Color color) { ); } + @Override + public boolean isBlack() { + return this.color.isBlack(); + } + + @Override + public String getName() { + return "나"; + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 95c563e2150..cc8598e36b8 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -19,6 +19,7 @@ public Pawn(Color color, Position position) { this.position = position; } + @Override public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step =calculateStep(targetPosition); @@ -93,6 +94,16 @@ public static List initialize(Color color) { return pieces; } + @Override + public boolean isBlack() { + return this.color.isBlack(); + } + + @Override + public String getName() { + return "폰"; + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java index eaab6845b2f..74daeec35d1 100644 --- a/src/main/java/chess/piece/Piece.java +++ b/src/main/java/chess/piece/Piece.java @@ -1,7 +1,14 @@ package chess.piece; +import chess.Board; import chess.Position; public interface Piece { Position getPosition(); + + String getName(); + + boolean isBlack(); + + void move(Position targetPosition, Board board); } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 974ba5d2452..1fb291912e5 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -18,6 +18,7 @@ public Queen(Color color, Position position) { this.position = position; } + @Override public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); @@ -88,6 +89,16 @@ public static List initialize(Color color) { return List.of(new Queen(color, new Position(Column.D, Row.EIGHT))); } + @Override + public boolean isBlack() { + return this.color.isBlack(); + } + + @Override + public String getName() { + return "퀸"; + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index ef977267c6c..6c875b9793c 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -6,7 +6,6 @@ import chess.Movement; import chess.Position; import chess.Row; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -19,6 +18,7 @@ public Rook(Color color, Position position) { this.position = position; } + @Override public void move(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); @@ -73,6 +73,16 @@ public static List initialize(Color color) { ); } + @Override + public boolean isBlack() { + return this.color.isBlack(); + } + + @Override + public String getName() { + return "룩"; + } + @Override public Position getPosition() { return this.position; diff --git a/src/main/java/chess/view/BoardView.java b/src/main/java/chess/view/BoardView.java new file mode 100644 index 00000000000..f1c1ceb0f63 --- /dev/null +++ b/src/main/java/chess/view/BoardView.java @@ -0,0 +1,53 @@ +package chess.view; + +import chess.Board; +import chess.Column; +import chess.Position; +import chess.Row; +import chess.piece.Piece; +import java.util.Arrays; + +public class BoardView { + private static final int MAX_COLUMN = 8; + private static final int MAX_ROW = 8; + + private static final String GREEN_CODE = "\u001B[32m"; + private static final String WHITE_CODE = "\u001B[37m"; + private static final String BLACK_CODE = "\u001B[30m"; + private static final String COLOR_FINISH_CODE = "\u001B[0m"; + + + private static final String[][] matrix = new String[MAX_ROW + 1][MAX_COLUMN + 1]; + + public static void printBoard(Board board) { + clearBoard(); + for (Piece piece : board.getPieces()) { + Position position = piece.getPosition(); + matrix[position.getRow() + 1][position.getColumn() + 1] = getPieceNameMessage(piece); + } + + for (String[] row : matrix) { + System.out.println(String.join(" | ", row)); + } + } + + private static String getPieceNameMessage(Piece piece) { + if (piece.isBlack()) { + return GREEN_CODE + piece.getName() + COLOR_FINISH_CODE; + } + return WHITE_CODE + piece.getName() + COLOR_FINISH_CODE; + } + + private static void clearBoard() { + for (int row = 0; row < MAX_ROW + 1; row++) { + Arrays.fill(matrix[row], BLACK_CODE + "ㅁ" + COLOR_FINISH_CODE); + if (row == 0) { + for (int column = 0; column < MAX_COLUMN; column++) { + matrix[row][column + 1] = Column.ofOrdinal(column); + } + continue; + } + matrix[row][0] = Row.ofOrdinal(row - 1); + } + } +} diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java new file mode 100644 index 00000000000..36fce128548 --- /dev/null +++ b/src/main/java/chess/view/InputView.java @@ -0,0 +1,29 @@ +package chess.view; + +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.Scanner; + +public class InputView { + private static final Scanner sc = new Scanner(System.in); + + //TODO 입력값 예외 처리 + public static Position readMovingPosition() { + System.out.println("\n움직일 기물의 열과 행을 선택해주세요. (ex. a,1)"); + String[] input = sc.nextLine().split(","); + return new Position( + Column.valueOf(input[0].toUpperCase()), + Row.fromNumber(Integer.parseInt(input[1])) + ); + } + + public static Position readTargetPosition() { + System.out.println("어느 열과 행으로 움직일지 선택해주세요. (ex. b,2)"); + String[] input = sc.nextLine().split(","); + return new Position( + Column.valueOf(input[0].toUpperCase()), + Row.fromNumber(Integer.parseInt(input[1])) + ); + } +} From 62f7a6fa317862c27ff55bfd5b1728bc667f1bb5 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 18:58:37 +0900 Subject: [PATCH 13/19] =?UTF-8?q?feat=20:=20=ED=8F=B0=EC=9D=B4=20=EB=92=A4?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=80=EB=8A=94=20=EA=B2=83=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Pawn.java | 30 +++++++++++++++++------ src/test/java/chess/piece/PawnTest.java | 32 +++++++++++++++++++++---- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index cc8598e36b8..6f948974794 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -47,19 +47,35 @@ private Movement findMovement(Position targetPosition) { //TODO 앞으로만 갈수 있음 int columnGap = position.calculateColumnGap(targetPosition); int rowGap = position.calculateRowGap(targetPosition); + Movement movement = null; if (rowGap == 0) { - if (position.calculateColumnGap(targetPosition) > 0) { - return Movement.LEFT; + if (columnGap > 0) { + movement = Movement.LEFT; + } + if (columnGap < 0) { + movement = Movement.RIGHT; } - return Movement.RIGHT; } if (columnGap == 0) { - if (position.calculateRowGap(targetPosition) > 0) { - return Movement.UP; + if (rowGap > 0) { + movement = Movement.UP; + } + if (rowGap < 0) { + movement = Movement.DOWN; } - return Movement.DOWN; } - throw new IllegalArgumentException("폰은 동서남북 방향으로만 이동 가능합니다."); + validateAvailableDirection(movement); + return movement; + } + + private void validateAvailableDirection(Movement movement) { + if (movement == null) { + throw new IllegalArgumentException("폰은 동서남북 방향으로만 이동 가능합니다."); + } + if ((movement == Movement.DOWN && color.isWhite()) + || (movement == Movement.UP && color.isBlack())) { + throw new IllegalArgumentException("폰은 뒤로 이동할 수 없습니다."); + } } private void repeatMove(Movement movement, Board board, int step) { diff --git a/src/test/java/chess/piece/PawnTest.java b/src/test/java/chess/piece/PawnTest.java index 1d3766c0eba..89056f1b535 100644 --- a/src/test/java/chess/piece/PawnTest.java +++ b/src/test/java/chess/piece/PawnTest.java @@ -25,6 +25,18 @@ void moveUpOnce() { assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.THREE))); } + @Test + void moveDownOnce() { + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.THREE)); + Board board = new Board(List.of( + pawn + )); + + pawn.move(new Position(Column.A, Row.TWO), board); + + assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.TWO))); + } + @Test void failToMoveUpMoreThanOnce() { Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); @@ -61,14 +73,24 @@ void failIfHurdleExists() { } @Test - void moveDownOnce() { - Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.THREE)); - Board board = new Board(List.of( + void failIfMoveBackWhenColorBlack() { + Pawn pawn = new Pawn(Color.BLACK, new Position(Column.A, Row.SEVEN)); + Board hurdleBoard = new Board(List.of( pawn )); - pawn.move(new Position(Column.A, Row.TWO), board); + assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.EIGHT), hurdleBoard)) + .isInstanceOf(IllegalArgumentException.class); + } - assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.TWO))); + @Test + void failIfMoveBackWhenColorWhite() { + Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); + Board hurdleBoard = new Board(List.of( + pawn + )); + + assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.ONE), hurdleBoard)) + .isInstanceOf(IllegalArgumentException.class); } } From 7e3b7a9407ccfe53979f9a57cc8e82e5abbdcede Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 19:33:57 +0900 Subject: [PATCH 14/19] =?UTF-8?q?feat=20:=20=ED=8F=B0=EC=9D=98=20=EA=B3=B5?= =?UTF-8?q?=EA=B2=A9=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Board.java | 7 +- src/main/java/chess/piece/Bishop.java | 10 ++- src/main/java/chess/piece/King.java | 10 ++- src/main/java/chess/piece/Knight.java | 10 ++- src/main/java/chess/piece/Pawn.java | 87 ++++++++++++++++++++--- src/main/java/chess/piece/Piece.java | 4 +- src/main/java/chess/piece/Queen.java | 10 ++- src/main/java/chess/piece/Rook.java | 10 ++- src/test/java/chess/piece/BishopTest.java | 12 ++-- src/test/java/chess/piece/KingTest.java | 22 +++--- src/test/java/chess/piece/KnightTest.java | 12 ++-- src/test/java/chess/piece/PawnTest.java | 26 +++---- src/test/java/chess/piece/QueenTest.java | 16 ++--- src/test/java/chess/piece/RookTest.java | 16 ++--- 14 files changed, 182 insertions(+), 70 deletions(-) diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java index 61e0f9516f6..7002cf01260 100644 --- a/src/main/java/chess/Board.java +++ b/src/main/java/chess/Board.java @@ -56,6 +56,11 @@ public Piece findByPositionOrThrow(Position position) { } public void move(Piece movingPiece, Position targetPosition) { - movingPiece.move(targetPosition, this); + movingPiece.moveTo(targetPosition, this); + } + + public void remove(Position targetPosition) { + Piece piece = findByPositionOrThrow(targetPosition); + this.pieces.remove(piece); } } diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 09f607fa4ef..b95dfbcf1c8 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -19,7 +19,7 @@ public Bishop(Color color, Position position) { } @Override - public void move(Position targetPosition, Board board) { + public void moveTo(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); repeatMove(movement, board, step); @@ -81,6 +81,14 @@ public static List initialize(Color color) { ); } + @Override + public boolean isEnemyWith(Piece piece) { + if (this.isBlack()) { + return !piece.isBlack(); + } + return piece.isBlack(); + } + @Override public boolean isBlack() { return this.color.isBlack(); diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 4f66a406788..2f4b40574c2 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -19,7 +19,7 @@ public King(Color color, Position position) { } @Override - public void move(Position targetPosition, Board board) { + public void moveTo(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); if (step != 1) { @@ -82,6 +82,14 @@ public static List initialize(Color color) { return List.of(new King(color, new Position(Column.E, Row.EIGHT))); } + @Override + public boolean isEnemyWith(Piece piece) { + if (this.isBlack()) { + return !piece.isBlack(); + } + return piece.isBlack(); + } + @Override public boolean isBlack() { return this.color.isBlack(); diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index bf71984dccf..67dcb43df1b 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -19,7 +19,7 @@ public Knight(Color color, Position position) { } @Override - public void move(Position targetPosition, Board board) { + public void moveTo(Position targetPosition, Board board) { List movements = findMovement(targetPosition); repeatMove(movements, board); } @@ -87,6 +87,14 @@ public static List initialize(Color color) { ); } + @Override + public boolean isEnemyWith(Piece piece) { + if (this.isBlack()) { + return !piece.isBlack(); + } + return piece.isBlack(); + } + @Override public boolean isBlack() { return this.color.isBlack(); diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 6f948974794..1671019d44b 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; public class Pawn implements Piece { private final Color color; @@ -20,9 +21,10 @@ public Pawn(Color color, Position position) { } @Override - public void move(Position targetPosition, Board board) { + public void moveTo(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); - int step =calculateStep(targetPosition); + validateAvailableDirection(movement, board, targetPosition); + int step = calculateStep(targetPosition); if (isMovingInitially()) { if (step > 2 || step == 0) { throw new IllegalArgumentException("폰은 시작 시 1칸 또는 2칸만 전진할 수 있습니다."); @@ -44,7 +46,6 @@ private int calculateStep(Position targetPosition) { } private Movement findMovement(Position targetPosition) { - //TODO 앞으로만 갈수 있음 int columnGap = position.calculateColumnGap(targetPosition); int rowGap = position.calculateRowGap(targetPosition); Movement movement = null; @@ -64,31 +65,87 @@ private Movement findMovement(Position targetPosition) { movement = Movement.DOWN; } } - validateAvailableDirection(movement); + if (rowGap > 0) { + if (columnGap > 0) { + movement = Movement.LEFT_UP; + } + if (columnGap < 0) { + movement = Movement.RIGHT_UP; + } + } + if (rowGap < 0) { + if (columnGap > 0) { + movement = Movement.LEFT_DOWN; + } + if (columnGap < 0) { + movement = Movement.RIGHT_DOWN; + } + } return movement; } - private void validateAvailableDirection(Movement movement) { + private void validateAvailableDirection(Movement movement, Board board, Position targetPosition) { if (movement == null) { throw new IllegalArgumentException("폰은 동서남북 방향으로만 이동 가능합니다."); } - if ((movement == Movement.DOWN && color.isWhite()) - || (movement == Movement.UP && color.isBlack())) { - throw new IllegalArgumentException("폰은 뒤로 이동할 수 없습니다."); + if (color.isWhite()) { + if (movement == Movement.DOWN + || movement == Movement.LEFT_DOWN + || movement == Movement.RIGHT_DOWN + ) { + throw new IllegalArgumentException("폰은 뒤로 이동할 수 없습니다."); + } + } + if (color.isBlack()) { + if (movement == Movement.UP + || movement == Movement.LEFT_UP + || movement == Movement.RIGHT_UP + ) { + throw new IllegalArgumentException("폰은 뒤로 이동할 수 없습니다."); + } + } + if (movement.isDiagonal()) { + if (board.findByPosition(targetPosition).isEmpty()) { + throw new IllegalArgumentException("폰은 공격 시에만 대각선으로 이동할 수 있습니다."); + } } } private void repeatMove(Movement movement, Board board, int step) { - for (int s = 0; s < step; s++) { + for (int pointer = 0; pointer < step; pointer++) { if (!this.position.canMove(movement)) { throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); } Position newPosition = this.position.move(movement); - if (board.findByPosition(newPosition).isPresent()) { - throw new IllegalArgumentException("장애물이 존재합니다."); + + if (canAttack(movement, step, pointer)) { + attack(board, newPosition); + } else { + simplyMove(board, newPosition); } + } + } + + private static boolean canAttack(Movement movement, int step, int pointer) { + return pointer == step - 1 + && movement.isDiagonal(); + } + + private void simplyMove(Board board, Position newPosition) { + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + + private void attack(Board board, Position newPosition) { + Optional existingPiece = board.findByPosition(newPosition); + if (existingPiece.isPresent() && existingPiece.get().isEnemyWith(this)) { this.position = newPosition; + board.remove(newPosition); + return; } + throw new IllegalArgumentException("공격할 수 없습니다."); } private boolean isMovingInitially() { @@ -110,6 +167,14 @@ public static List initialize(Color color) { return pieces; } + @Override + public boolean isEnemyWith(Piece piece) { + if (this.isBlack()) { + return !piece.isBlack(); + } + return piece.isBlack(); + } + @Override public boolean isBlack() { return this.color.isBlack(); diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java index 74daeec35d1..9733b86ece1 100644 --- a/src/main/java/chess/piece/Piece.java +++ b/src/main/java/chess/piece/Piece.java @@ -10,5 +10,7 @@ public interface Piece { boolean isBlack(); - void move(Position targetPosition, Board board); + void moveTo(Position targetPosition, Board board); + + boolean isEnemyWith(Piece piece); } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 1fb291912e5..8e5e94c6a62 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -19,7 +19,7 @@ public Queen(Color color, Position position) { } @Override - public void move(Position targetPosition, Board board) { + public void moveTo(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); repeatMove(movement, board, step); @@ -89,6 +89,14 @@ public static List initialize(Color color) { return List.of(new Queen(color, new Position(Column.D, Row.EIGHT))); } + @Override + public boolean isEnemyWith(Piece piece) { + if (this.isBlack()) { + return !piece.isBlack(); + } + return piece.isBlack(); + } + @Override public boolean isBlack() { return this.color.isBlack(); diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 6c875b9793c..5a6aff8789b 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -19,7 +19,7 @@ public Rook(Color color, Position position) { } @Override - public void move(Position targetPosition, Board board) { + public void moveTo(Position targetPosition, Board board) { Movement movement = findMovement(targetPosition); int step = calculateStep(targetPosition); repeatMove(movement, board, step); @@ -73,6 +73,14 @@ public static List initialize(Color color) { ); } + @Override + public boolean isEnemyWith(Piece piece) { + if (this.isBlack()) { + return !piece.isBlack(); + } + return piece.isBlack(); + } + @Override public boolean isBlack() { return this.color.isBlack(); diff --git a/src/test/java/chess/piece/BishopTest.java b/src/test/java/chess/piece/BishopTest.java index bf8a67c7228..c0d045a2a62 100644 --- a/src/test/java/chess/piece/BishopTest.java +++ b/src/test/java/chess/piece/BishopTest.java @@ -14,27 +14,27 @@ class BishopTest { @Test - void moveLeftUpTwice() { + void moveToLeftUpTwice() { Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( bishop )); Position newPosition = new Position(Column.C, Row.SEVEN); - bishop.move(newPosition, board); + bishop.moveTo(newPosition, board); assertThat(bishop).isEqualTo(new Bishop(Color.WHITE, newPosition)); } @Test - void failIfCardinalMove() { + void failIfCardinalMoveTo() { Bishop bishop = new Bishop(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( bishop )); Position newPosition = new Position(Column.C, Row.FIVE); - assertThatThrownBy(() -> bishop.move(newPosition, board)) + assertThatThrownBy(() -> bishop.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } @@ -46,7 +46,7 @@ void failIfNotStraight() { )); Position newPosition = new Position(Column.G, Row.SIX); - assertThatThrownBy(() -> bishop.move(newPosition, board)) + assertThatThrownBy(() -> bishop.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } @@ -59,7 +59,7 @@ void failIfHurdleExists() { )); Position newPosition = new Position(Column.C, Row.SEVEN); - assertThatThrownBy(() -> bishop.move(newPosition, board)) + assertThatThrownBy(() -> bishop.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java index 79de067156c..ffd6771c1cd 100644 --- a/src/test/java/chess/piece/KingTest.java +++ b/src/test/java/chess/piece/KingTest.java @@ -13,62 +13,62 @@ class KingTest { @Test - void moveUpOnce() { + void moveToUpOnce() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( king )); - king.move(new Position(Column.E, Row.SIX), board); + king.moveTo(new Position(Column.E, Row.SIX), board); assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.E, Row.SIX))); } @Test - void moveRightOnce() { + void moveToRightOnce() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( king )); Position newPosition = new Position(Column.F, Row.FIVE); - king.move(newPosition, board); + king.moveTo(newPosition, board); assertThat(king).isEqualTo(new King(Color.WHITE, newPosition)); } @Test - void moveLeftUpOnce() { + void moveToLeftUpOnce() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( king )); - king.move(new Position(Column.D, Row.SIX), board); + king.moveTo(new Position(Column.D, Row.SIX), board); assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.D, Row.SIX))); } @Test - void moveRightDownOnce() { + void moveToRightDownOnce() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( king )); - king.move(new Position(Column.F, Row.FOUR), board); + king.moveTo(new Position(Column.F, Row.FOUR), board); assertThat(king).isEqualTo(new King(Color.WHITE, new Position(Column.F, Row.FOUR))); } @Test - void failToMoveTwice() { + void failToMoveToTwice() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( king )); - assertThatThrownBy(() -> king.move(new Position(Column.E, Row.THREE), board)) + assertThatThrownBy(() -> king.moveTo(new Position(Column.E, Row.THREE), board)) .isInstanceOf(IllegalArgumentException.class); } @@ -79,7 +79,7 @@ void failIfNotStraight() { king )); - assertThatThrownBy(() -> king.move(new Position(Column.D, Row.THREE), board)) + assertThatThrownBy(() -> king.moveTo(new Position(Column.D, Row.THREE), board)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/chess/piece/KnightTest.java b/src/test/java/chess/piece/KnightTest.java index 5825af64e5a..2b95b4b4165 100644 --- a/src/test/java/chess/piece/KnightTest.java +++ b/src/test/java/chess/piece/KnightTest.java @@ -13,20 +13,20 @@ class KnightTest { @Test - void moveUpUpLeftOnce() { + void moveToUpUpLeftOnce() { Knight knight = new Knight(Color.WHITE, new Position(Column.D, Row.FIVE)); Board board = new Board(List.of( knight )); Position newPosition = new Position(Column.C, Row.SEVEN); - knight.move(newPosition, board); + knight.moveTo(newPosition, board); assertThat(knight).isEqualTo(new Knight(Color.WHITE, newPosition)); } @Test - void moveRightRightDownOnce() { + void moveToRightRightDownOnce() { Knight knight = new Knight(Color.WHITE, new Position(Column.D, Row.FIVE)); Board board = new Board(List.of( knight @@ -34,20 +34,20 @@ void moveRightRightDownOnce() { Position newPosition = new Position(Column.F, Row.FOUR); - knight.move(newPosition, board); + knight.moveTo(newPosition, board); assertThat(knight).isEqualTo(new Knight(Color.WHITE, newPosition)); } @Test - void failToMoveOther() { + void failToMoveToOther() { King king = new King(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( king )); Position newPosition = new Position(Column.F, Row.THREE); - assertThatThrownBy(() -> king.move(newPosition, board)) + assertThatThrownBy(() -> king.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/chess/piece/PawnTest.java b/src/test/java/chess/piece/PawnTest.java index 89056f1b535..d1128f26d84 100644 --- a/src/test/java/chess/piece/PawnTest.java +++ b/src/test/java/chess/piece/PawnTest.java @@ -14,48 +14,48 @@ public class PawnTest { @Test - void moveUpOnce() { + void moveToUpOnce() { Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); Board board = new Board(List.of( pawn )); - pawn.move(new Position(Column.A, Row.THREE), board); + pawn.moveTo(new Position(Column.A, Row.THREE), board); assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.THREE))); } @Test - void moveDownOnce() { + void moveToDownOnce() { Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.THREE)); Board board = new Board(List.of( pawn )); - pawn.move(new Position(Column.A, Row.TWO), board); + pawn.moveTo(new Position(Column.A, Row.TWO), board); assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.TWO))); } @Test - void failToMoveUpMoreThanOnce() { + void failToMoveToUpMoreThanOnce() { Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); Board board = new Board(List.of( pawn )); - assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.FIVE), board)) + assertThatThrownBy(() -> pawn.moveTo(new Position(Column.A, Row.FIVE), board)) .isInstanceOf(IllegalArgumentException.class); } @Test - void moveUpTwiceIfStartMoving() { + void moveToUpTwiceIfStartMoving() { Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); Board board = new Board(List.of( pawn )); - pawn.move(new Position(Column.A, Row.FOUR), board); + pawn.moveTo(new Position(Column.A, Row.FOUR), board); assertThat(pawn).isEqualTo(new Pawn(Color.WHITE, new Position(Column.A, Row.FOUR))); } @@ -68,29 +68,29 @@ void failIfHurdleExists() { pawn )); - assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.FOUR), hurdleBoard)) + assertThatThrownBy(() -> pawn.moveTo(new Position(Column.A, Row.FOUR), hurdleBoard)) .isInstanceOf(IllegalArgumentException.class); } @Test - void failIfMoveBackWhenColorBlack() { + void failIfMoveToBackWhenColorBlack() { Pawn pawn = new Pawn(Color.BLACK, new Position(Column.A, Row.SEVEN)); Board hurdleBoard = new Board(List.of( pawn )); - assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.EIGHT), hurdleBoard)) + assertThatThrownBy(() -> pawn.moveTo(new Position(Column.A, Row.EIGHT), hurdleBoard)) .isInstanceOf(IllegalArgumentException.class); } @Test - void failIfMoveBackWhenColorWhite() { + void failIfMoveToBackWhenColorWhite() { Pawn pawn = new Pawn(Color.WHITE, new Position(Column.A, Row.TWO)); Board hurdleBoard = new Board(List.of( pawn )); - assertThatThrownBy(() -> pawn.move(new Position(Column.A, Row.ONE), hurdleBoard)) + assertThatThrownBy(() -> pawn.moveTo(new Position(Column.A, Row.ONE), hurdleBoard)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java index 0f67a31f2b8..3dcc3d8c2fb 100644 --- a/src/test/java/chess/piece/QueenTest.java +++ b/src/test/java/chess/piece/QueenTest.java @@ -13,40 +13,40 @@ class QueenTest { @Test - void moveUpTwice() { + void moveToUpTwice() { Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( queen )); Position newPosition = new Position(Column.E, Row.SEVEN); - queen.move(newPosition, board); + queen.moveTo(newPosition, board); assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); } @Test - void moveRightTwice() { + void moveToRightTwice() { Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( queen )); Position newPosition = new Position(Column.G, Row.FIVE); - queen.move(newPosition, board); + queen.moveTo(newPosition, board); assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); } @Test - void moveLeftUpTwice() { + void moveToLeftUpTwice() { Queen queen = new Queen(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( queen )); Position newPosition = new Position(Column.C, Row.SEVEN); - queen.move(newPosition, board); + queen.moveTo(newPosition, board); assertThat(queen).isEqualTo(new Queen(Color.WHITE, newPosition)); } @@ -60,7 +60,7 @@ void failIfHurdleExists() { )); Position newPosition = new Position(Column.E, Row.SEVEN); - assertThatThrownBy(() -> queen.move(newPosition, board)) + assertThatThrownBy(() -> queen.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } @@ -72,7 +72,7 @@ void failIfNotStraight() { )); Position newPosition = new Position(Column.F, Row.SEVEN); - assertThatThrownBy(() -> queen.move(newPosition, board)) + assertThatThrownBy(() -> queen.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/chess/piece/RookTest.java b/src/test/java/chess/piece/RookTest.java index f93cc1bd6ff..32bc4f0a0c0 100644 --- a/src/test/java/chess/piece/RookTest.java +++ b/src/test/java/chess/piece/RookTest.java @@ -13,40 +13,40 @@ class RookTest { @Test - void moveUpTwice() { + void moveToUpTwice() { Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( rook )); Position newPosition = new Position(Column.E, Row.SEVEN); - rook.move(newPosition, board); + rook.moveTo(newPosition, board); assertThat(rook).isEqualTo(new Rook(Color.WHITE, newPosition)); } @Test - void moveRightTwice() { + void moveToRightTwice() { Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( rook )); Position newPosition = new Position(Column.G, Row.FIVE); - rook.move(newPosition, board); + rook.moveTo(newPosition, board); assertThat(rook).isEqualTo(new Rook(Color.WHITE, newPosition)); } @Test - void failIfDiagonalMove() { + void failIfDiagonalMoveTo() { Rook rook = new Rook(Color.WHITE, new Position(Column.E, Row.FIVE)); Board board = new Board(List.of( rook )); Position newPosition = new Position(Column.D, Row.FOUR); - assertThatThrownBy(() -> rook.move(newPosition, board)) + assertThatThrownBy(() -> rook.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } @@ -59,7 +59,7 @@ void failIfHurdleExists() { )); Position newPosition = new Position(Column.E, Row.SEVEN); - assertThatThrownBy(() -> rook.move(newPosition, board)) + assertThatThrownBy(() -> rook.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } @@ -71,7 +71,7 @@ void failIfNotStraight() { )); Position newPosition = new Position(Column.F, Row.SEVEN); - assertThatThrownBy(() -> rook.move(newPosition, board)) + assertThatThrownBy(() -> rook.moveTo(newPosition, board)) .isInstanceOf(IllegalArgumentException.class); } } From 6265b696ba0a85470833581beac2c7a2a515d3a0 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 19:54:28 +0900 Subject: [PATCH 15/19] =?UTF-8?q?feat=20:=20=ED=82=B9=EC=9D=98=20=EA=B3=B5?= =?UTF-8?q?=EA=B2=A9=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/King.java | 35 ++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 2f4b40574c2..de767e32587 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -8,6 +8,7 @@ import chess.Row; import java.util.List; import java.util.Objects; +import java.util.Optional; public class King implements Piece { private final Color color; @@ -25,7 +26,7 @@ public void moveTo(Position targetPosition, Board board) { if (step != 1) { throw new IllegalArgumentException("킹은 1칸만 전진할 수 있습니다."); } - repeatMove(movement, board); + repeatMove(movement, board, 1); } private Movement findMovement(Position targetPosition) { @@ -64,11 +65,35 @@ private int calculateStep(Position targetPosition) { return Math.abs(rowGap); } - private void repeatMove(Movement movement, Board board) { - if (!this.position.canMove(movement)) { - throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + private void repeatMove(Movement movement, Board board, int step) { + for (int pointer = 0; pointer < step; pointer++) { + if (!this.position.canMove(movement)) { + throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); + } + Position newPosition = this.position.move(movement); + if (canAttack(step, pointer, board, newPosition)) { + attack(board, newPosition); + } else { + simplyMove(board, newPosition); + } + } + } + + private boolean canAttack(int step, int pointer, Board board, Position newPosition) { + if (pointer == step - 1) { + Optional existingPiece = board.findByPosition(newPosition); + return existingPiece.isPresent() + && existingPiece.get().isEnemyWith(this); } - Position newPosition = this.position.move(movement); + return false; + } + + private void attack(Board board, Position newPosition) { + this.position = newPosition; + board.remove(newPosition); + } + + private void simplyMove(Board board, Position newPosition) { if (board.findByPosition(newPosition).isPresent()) { throw new IllegalArgumentException("장애물이 존재합니다."); } From 448040b27e4de5f203e031c5a86c3c2c665c55dd Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 19:57:15 +0900 Subject: [PATCH 16/19] =?UTF-8?q?feat=20:=20=EB=82=98=EC=9D=B4=ED=8A=B8?= =?UTF-8?q?=EC=9D=98=20=EA=B3=B5=EA=B2=A9=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Knight.java | 32 ++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 67dcb43df1b..7335a5d887c 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -8,6 +8,7 @@ import chess.Row; import java.util.List; import java.util.Objects; +import java.util.Optional; public class Knight implements Piece { private final Color color; @@ -33,18 +34,43 @@ private List findMovement(Position targetPosition) { } private void repeatMove(List movements, Board board) { + int step = 0; for (Movement movement : movements) { + step++; if (!this.position.canMove(movement)) { throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); } Position newPosition = this.position.move(movement); - if (board.findByPosition(newPosition).isPresent()) { - throw new IllegalArgumentException("장애물이 존재합니다."); + + if (canAttack(step, board, newPosition)) { + attack(board, newPosition); + } else { + simplyMove(board, newPosition); } - this.position = newPosition; } } + private boolean canAttack(int step, Board board, Position newPosition) { + if (step == 3) { + Optional existingPiece = board.findByPosition(newPosition); + return existingPiece.isPresent() + && existingPiece.get().isEnemyWith(this); + } + return false; + } + + private void attack(Board board, Position newPosition) { + this.position = newPosition; + board.remove(newPosition); + } + + private void simplyMove(Board board, Position newPosition) { + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + private static Movement decideFirstMovement(int rowGap, int columnGap) { if (rowGap == 2) { return Movement.UP; From 41350a9173579218a058bc2442da8002910f9c06 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 19:59:33 +0900 Subject: [PATCH 17/19] =?UTF-8?q?feat=20:=20=ED=80=B8=EC=9D=98=20=EA=B3=B5?= =?UTF-8?q?=EA=B2=A9=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Queen.java | 35 +++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 8e5e94c6a62..0d23a3d40ba 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -8,6 +8,7 @@ import chess.Row; import java.util.List; import java.util.Objects; +import java.util.Optional; public class Queen implements Piece { private final Color color; @@ -70,16 +71,44 @@ private int calculateStep(Position targetPosition) { } private void repeatMove(Movement movement, Board board, int step) { - for (int s = 0; s < step; s++) { + for (int pointer = 0; pointer < step; pointer++) { if (!this.position.canMove(movement)) { throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); } Position newPosition = this.position.move(movement); - if (board.findByPosition(newPosition).isPresent()) { - throw new IllegalArgumentException("장애물이 존재합니다."); + + if (canAttack(step, pointer, board, newPosition)) { + attack(board, newPosition); + } else { + simplyMove(board, newPosition); } + } + } + + private boolean canAttack(int step, int pointer, Board board, Position newPosition) { + if (pointer == step - 1) { + Optional existingPiece = board.findByPosition(newPosition); + return existingPiece.isPresent() + && existingPiece.get().isEnemyWith(this); + } + return false; + } + + private void simplyMove(Board board, Position newPosition) { + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + + private void attack(Board board, Position newPosition) { + Optional existingPiece = board.findByPosition(newPosition); + if (existingPiece.isPresent() && existingPiece.get().isEnemyWith(this)) { this.position = newPosition; + board.remove(newPosition); + return; } + throw new IllegalArgumentException("공격할 수 없습니다."); } public static List initialize(Color color) { From 1bb1522ff2abbef355e5e0dd2592b863660db653 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 20:01:30 +0900 Subject: [PATCH 18/19] =?UTF-8?q?feat=20:=20=EB=A3=A9=EC=9D=98=20=EA=B3=B5?= =?UTF-8?q?=EA=B2=A9=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Queen.java | 9 ++------ src/main/java/chess/piece/Rook.java | 32 ++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 0d23a3d40ba..45fb120fac3 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -102,13 +102,8 @@ private void simplyMove(Board board, Position newPosition) { } private void attack(Board board, Position newPosition) { - Optional existingPiece = board.findByPosition(newPosition); - if (existingPiece.isPresent() && existingPiece.get().isEnemyWith(this)) { - this.position = newPosition; - board.remove(newPosition); - return; - } - throw new IllegalArgumentException("공격할 수 없습니다."); + this.position = newPosition; + board.remove(newPosition); } public static List initialize(Color color) { diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 5a6aff8789b..b17f058deef 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -8,6 +8,7 @@ import chess.Row; import java.util.List; import java.util.Objects; +import java.util.Optional; public class Rook implements Piece { private final Color color; @@ -51,18 +52,41 @@ private Movement findMovement(Position targetPosition) { } private void repeatMove(Movement movement, Board board, int step) { - for (int s = 0; s < step; s++) { + for (int pointer = 0; pointer < step; pointer++) { if (!this.position.canMove(movement)) { throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); } Position newPosition = this.position.move(movement); - if (board.findByPosition(newPosition).isPresent()) { - throw new IllegalArgumentException("장애물이 존재합니다."); + + if (canAttack(step, pointer, board, newPosition)) { + attack(board, newPosition); + } else { + simplyMove(board, newPosition); } - this.position = newPosition; } } + private boolean canAttack(int step, int pointer, Board board, Position newPosition) { + if (pointer == step - 1) { + Optional existingPiece = board.findByPosition(newPosition); + return existingPiece.isPresent() + && existingPiece.get().isEnemyWith(this); + } + return false; + } + + private void simplyMove(Board board, Position newPosition) { + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + + private void attack(Board board, Position newPosition) { + this.position = newPosition; + board.remove(newPosition); + } + public static List initialize(Color color) { Position standard = new Position(Column.A, Row.ONE); if (color.isBlack()) { From 47e8afcb71f485fea798c261a9f52669a4cfe123 Mon Sep 17 00:00:00 2001 From: Chaeyoung714 <202102760@hufs.ac.kr> Date: Sat, 22 Mar 2025 20:02:04 +0900 Subject: [PATCH 19/19] =?UTF-8?q?feat=20:=20=EB=B9=84=EC=88=8D=EC=9D=98=20?= =?UTF-8?q?=EA=B3=B5=EA=B2=A9=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Bishop.java | 32 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index b95dfbcf1c8..6432ed42b8b 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -8,6 +8,7 @@ import chess.Row; import java.util.List; import java.util.Objects; +import java.util.Optional; public class Bishop implements Piece{ private final Color color; @@ -59,18 +60,41 @@ private int calculateStep(Position targetPosition) { } private void repeatMove(Movement movement, Board board, int step) { - for (int s = 0; s < step; s++) { + for (int pointer = 0; pointer < step; pointer++) { if (!this.position.canMove(movement)) { throw new IllegalArgumentException("보드의 범위를 벗어난 위치입니다."); } Position newPosition = this.position.move(movement); - if (board.findByPosition(newPosition).isPresent()) { - throw new IllegalArgumentException("장애물이 존재합니다."); + + if (canAttack(step, pointer, board, newPosition)) { + attack(board, newPosition); + } else { + simplyMove(board, newPosition); } - this.position = newPosition; } } + private boolean canAttack(int step, int pointer, Board board, Position newPosition) { + if (pointer == step - 1) { + Optional existingPiece = board.findByPosition(newPosition); + return existingPiece.isPresent() + && existingPiece.get().isEnemyWith(this); + } + return false; + } + + private void simplyMove(Board board, Position newPosition) { + if (board.findByPosition(newPosition).isPresent()) { + throw new IllegalArgumentException("장애물이 존재합니다."); + } + this.position = newPosition; + } + + private void attack(Board board, Position newPosition) { + this.position = newPosition; + board.remove(newPosition); + } + public static List initialize(Color color) { Position standard = new Position(Column.C, Row.ONE); if (color.isBlack()) {