From 5e126134290036ef23f5476d726f52e77746b1c2 Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 14:45:38 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20King=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=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/ChessBoard.java | 43 +++++++++++++++++ src/main/java/chess/piece/Bishop.java | 14 +++++- src/main/java/chess/piece/King.java | 30 +++++++++++- src/main/java/chess/piece/Knight.java | 33 ++++++++++++- src/main/java/chess/piece/Pawn.java | 14 +++++- src/main/java/chess/piece/Piece.java | 62 +++++++++++++++++++++++++ src/main/java/chess/piece/Queen.java | 14 +++++- src/main/java/chess/piece/Rook.java | 35 +++++++++++++- src/test/java/chess/piece/KingTest.java | 54 +++++++++++++++++++++ 9 files changed, 293 insertions(+), 6 deletions(-) create mode 100644 src/main/java/chess/ChessBoard.java create mode 100644 src/main/java/chess/piece/Piece.java create mode 100644 src/test/java/chess/piece/KingTest.java diff --git a/src/main/java/chess/ChessBoard.java b/src/main/java/chess/ChessBoard.java new file mode 100644 index 0000000000..8e703c5c36 --- /dev/null +++ b/src/main/java/chess/ChessBoard.java @@ -0,0 +1,43 @@ +package chess; + +import chess.piece.Piece; +import java.util.List; + +public class ChessBoard { + + private final List pieces; + + public ChessBoard(List pieces) { + this.pieces = pieces; + } + + public void move(Color color, Position from, Position to) { + if (isNotExistPiece(from)) { + throw new IllegalArgumentException("출발지에 기물이 없습니다."); + } + findPiece(from).move(this, color, to); + } + + public boolean isExistPiece(Position position) { + return pieces.stream() + .anyMatch(piece -> piece.isPosition(position)); + } + + public boolean isNotExistPiece(Position position) { + return !isExistPiece(position); + } + + public boolean isColorInPosition(Color color, Position position) { + if (isNotExistPiece(position)) { + return false; + } + return findPiece(position).isColor(color); + } + + public Piece findPiece(Position position) { + return pieces.stream() + .filter(piece -> piece.isPosition(position)) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index b14ab70f98..341502772d 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -1,5 +1,17 @@ package chess.piece; -public class Bishop { +import chess.ChessBoard; +import chess.Color; +import chess.Position; +public class Bishop extends Piece { + + public Bishop(Color color, Position position) { + super(color, position); + } + + @Override + boolean isMovable(ChessBoard chessBoard, Position to) { + return false; + } } diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index d64210cad1..c140fb93e2 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -1,5 +1,33 @@ package chess.piece; -public class King { +import chess.ChessBoard; +import chess.Color; +import chess.Movement; +import chess.Position; +import java.util.Set; +public class King extends Piece { + + private static final Set MOVEMENTS = Set.of( + Movement.UP, Movement.DOWN, Movement.LEFT, Movement.RIGHT + ); + + public King(Color color, Position position) { + super(color, position); + } + + @Override + protected boolean isMovable(ChessBoard chessBoard, Position to) { + for (Movement movement : MOVEMENTS) { + Position curr = position; + if (!curr.canMove(movement)) { + break; + } + curr = curr.move(movement); + if (curr.equals(to)) { + return true; + } + } + return false; + } } diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 2ee7c47a3b..bcd4c893db 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -1,5 +1,36 @@ package chess.piece; -public class Knight { +import chess.ChessBoard; +import chess.Color; +import chess.Movement; +import chess.Position; +import java.util.Set; +public class Knight extends Piece { + + private static final Set MOVEMENTS = Set.of( + Movement.UP_UP_LEFT, Movement.UP_UP_RIGHT, + Movement.LEFT_LEFT_DOWN, Movement.LEFT_LEFT_UP, + Movement.RIGHT_RIGHT_DOWN, Movement.RIGHT_RIGHT_UP, + Movement.DOWN_DOWN_LEFT, Movement.DOWN_DOWN_RIGHT + ); + + public Knight(Color color, Position position) { + super(color, position); + } + + @Override + boolean isMovable(ChessBoard chessBoard, Position to) { + for (Movement movement : MOVEMENTS) { + Position curr = position; + if (!curr.canMove(movement)) { + break; + } + curr = position.move(movement); + if (curr.equals(to)) { + return true; + } + } + return false; + } } diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index c8b6cafa51..7208b62a19 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -1,5 +1,17 @@ package chess.piece; -public class Pawn { +import chess.ChessBoard; +import chess.Color; +import chess.Position; +public class Pawn extends Piece { + + public Pawn(Color color, Position position) { + super(color, position); + } + + @Override + boolean isMovable(ChessBoard chessBoard, Position to) { + return false; + } } diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java new file mode 100644 index 0000000000..036e38100f --- /dev/null +++ b/src/main/java/chess/piece/Piece.java @@ -0,0 +1,62 @@ +package chess.piece; + +import chess.ChessBoard; +import chess.Color; +import chess.Position; +import java.util.Objects; + +public abstract class Piece { + + private final Color color; + protected Position position; + + public Piece(Color color, Position position) { + this.color = color; + this.position = position; + } + + public void move(ChessBoard chessBoard, Color color, Position to) { + if (!isColor(color)) { + throw new IllegalArgumentException("자기팀의 기물이 아닙니다."); + } + if (chessBoard.isColorInPosition(color, to)) { + throw new IllegalArgumentException("목적지에 같은 팀의 기물이 있습니다."); + } + if (!isMovable(chessBoard, to)) { + throw new IllegalArgumentException("해당 목적지로 갈 수 없습니다."); + } + position = to; + } + + ; + + public boolean isColor(Color color) { + return this.color == color; + } + + public boolean isPosition(Position position) { + return this.position.equals(position); + } + + abstract boolean isMovable(ChessBoard chessBoard, Position to); + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + + Piece piece = (Piece) object; + return color == piece.color && Objects.equals(position, piece.position); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(color); + result = 31 * result + Objects.hashCode(position); + return result; + } +} diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 9b547261c4..2074a1a1dc 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -1,5 +1,17 @@ package chess.piece; -public class Queen { +import chess.ChessBoard; +import chess.Color; +import chess.Position; +public class Queen extends Piece { + + public Queen(Color color, Position position) { + super(color, position); + } + + @Override + boolean isMovable(ChessBoard chessBoard, Position to) { + return false; + } } diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 7ed4d08bf0..dcf8b77c6a 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -1,5 +1,38 @@ package chess.piece; -public class Rook { +import chess.ChessBoard; +import chess.Color; +import chess.Movement; +import chess.Position; +import java.util.Set; +public class Rook extends Piece { + + private static final Set MOVEMENTS = Set.of( + Movement.UP, Movement.DOWN, Movement.LEFT, Movement.RIGHT + ); + + public Rook(Color color, Position position) { + super(color, position); + } + + @Override + boolean isMovable(ChessBoard chessBoard, Position to) { + for (Movement movement : MOVEMENTS) { + Position curr = position; + while (curr.equals(to)) { + if (!curr.canMove(movement)) { + break; + } + curr = curr.move(movement); + if (chessBoard.isExistPiece(curr)) { + break; + } + } + if (curr.equals(to)) { + return true; + } + } + return false; + } } diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java new file mode 100644 index 0000000000..ddd8290feb --- /dev/null +++ b/src/test/java/chess/piece/KingTest.java @@ -0,0 +1,54 @@ +package chess.piece; + +import chess.ChessBoard; +import chess.Color; +import chess.Column; +import chess.Fixtures; +import chess.Position; +import chess.Row; +import java.util.List; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class KingTest { + + @ParameterizedTest + @MethodSource("provideMovablePosition") + void 킹은_상_하_좌_우_한칸_같은팀의_기물이_없다면_이동할_수_있다(Position from, Position to) { + //given + ChessBoard chessBoard = new ChessBoard(List.of()); + King king = new King(Color.BLACK, from); + + //when + boolean result = king.isMovable(chessBoard, to); + + //then + Assertions.assertThat(result).isTrue(); + } + + @Test + void 킹은_상_하_좌_우_한칸이_아닌_다른곳으로_이동할_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of()); + King king = new King(Color.BLACK, new Position(Column.B, Row.FIVE)); + + //when + boolean result = king.isMovable(chessBoard, new Position(Column.A, Row.THREE)); + + //then + Assertions.assertThat(result).isFalse(); + } + + private static Stream provideMovablePosition() { + return Stream.of( + Arguments.of(Fixtures.A1, Fixtures.A2), + Arguments.of(Fixtures.B2, Fixtures.B1), + Arguments.of(Fixtures.B1, Fixtures.C1), + Arguments.of(Fixtures.C2, Fixtures.B2) + ); + } +} From 4228d0ec68657023ee8fe869ac428b340acd51b4 Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 14:56:31 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20Knight=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=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 | 2 +- src/main/java/chess/piece/Knight.java | 4 +- src/test/java/chess/piece/KnightTest.java | 60 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/test/java/chess/piece/KnightTest.java diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index c140fb93e2..de19481009 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -21,7 +21,7 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; if (!curr.canMove(movement)) { - break; + continue; } curr = curr.move(movement); if (curr.equals(to)) { diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index bcd4c893db..ad1516473a 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -24,9 +24,9 @@ boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; if (!curr.canMove(movement)) { - break; + continue; } - curr = position.move(movement); + curr = curr.move(movement); if (curr.equals(to)) { return true; } diff --git a/src/test/java/chess/piece/KnightTest.java b/src/test/java/chess/piece/KnightTest.java new file mode 100644 index 0000000000..1edfabacba --- /dev/null +++ b/src/test/java/chess/piece/KnightTest.java @@ -0,0 +1,60 @@ +package chess.piece; + +import static chess.Fixtures.A1; +import static chess.Fixtures.A4; +import static chess.Fixtures.B1; +import static chess.Fixtures.B2; +import static chess.Fixtures.C2; +import static chess.Fixtures.C3; +import static org.assertj.core.api.Assertions.assertThat; + +import chess.ChessBoard; +import chess.Color; +import chess.Position; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class KnightTest { + + @ParameterizedTest + @MethodSource("provideMovablePosition") + void 나이트는_상하좌우_한칸_후_대각선_모든_방향으로_갈_수_있다(Position from, Position to) { + //given + ChessBoard chessBoard = new ChessBoard(List.of()); + Knight knight = new Knight(Color.BLACK, from); + + //when + boolean movable = knight.isMovable(chessBoard, to); + + //then + assertThat(movable).isTrue(); + } + + private static Stream provideMovablePosition() { + return Stream.of( + Arguments.of(A1, C2), + Arguments.of(B2, A4), + Arguments.of(C3, B1), + Arguments.of(B1, C3) + ); + } + + @Test + void 나이트가_가는방향에_기물이_있더라도_갈_수_있다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Pawn(Color.BLACK, B1) + )); + Knight knight = new Knight(Color.BLACK, A1); + + //when + boolean movable = knight.isMovable(chessBoard, C2); + + //then + assertThat(movable).isTrue(); + } +} From 21580fca77624cd192e765119374d76e088900ea Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 15:03:09 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20Rook=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=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/Rook.java | 2 +- src/test/java/chess/piece/KnightTest.java | 18 +++---- src/test/java/chess/piece/RookTest.java | 65 +++++++++++++++++++++++ 3 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 src/test/java/chess/piece/RookTest.java diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index dcf8b77c6a..0dfe68e59d 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -20,7 +20,7 @@ public Rook(Color color, Position position) { boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; - while (curr.equals(to)) { + while (!curr.equals(to)) { if (!curr.canMove(movement)) { break; } diff --git a/src/test/java/chess/piece/KnightTest.java b/src/test/java/chess/piece/KnightTest.java index 1edfabacba..0877952771 100644 --- a/src/test/java/chess/piece/KnightTest.java +++ b/src/test/java/chess/piece/KnightTest.java @@ -34,15 +34,6 @@ class KnightTest { assertThat(movable).isTrue(); } - private static Stream provideMovablePosition() { - return Stream.of( - Arguments.of(A1, C2), - Arguments.of(B2, A4), - Arguments.of(C3, B1), - Arguments.of(B1, C3) - ); - } - @Test void 나이트가_가는방향에_기물이_있더라도_갈_수_있다() { //given @@ -57,4 +48,13 @@ private static Stream provideMovablePosition() { //then assertThat(movable).isTrue(); } + + private static Stream provideMovablePosition() { + return Stream.of( + Arguments.of(A1, C2), + Arguments.of(B2, A4), + Arguments.of(C3, B1), + Arguments.of(B1, C3) + ); + } } diff --git a/src/test/java/chess/piece/RookTest.java b/src/test/java/chess/piece/RookTest.java new file mode 100644 index 0000000000..5ae97bd3a3 --- /dev/null +++ b/src/test/java/chess/piece/RookTest.java @@ -0,0 +1,65 @@ +package chess.piece; + +import static chess.Fixtures.A1; +import static chess.Fixtures.A8; +import static chess.Fixtures.B1; +import static chess.Fixtures.B2; +import static chess.Fixtures.B3; +import static chess.Fixtures.B4; +import static chess.Fixtures.B8; +import static chess.Fixtures.C1; +import static chess.Fixtures.C3; +import static chess.Fixtures.H2; +import static org.assertj.core.api.Assertions.assertThat; + +import chess.ChessBoard; +import chess.Color; +import chess.Position; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class RookTest { + + @ParameterizedTest + @MethodSource("provideMovablePosition") + void 룩은_상하좌우_보드_끝까지_갈_수_있다(Position from, Position to) { + //given + ChessBoard chessBoard = new ChessBoard(List.of()); + Rook rook = new Rook(Color.BLACK, from); + + //when + boolean movable = rook.isMovable(chessBoard, to); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 룩이_기는_방향에_기물이_있다면_갈_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Pawn(Color.BLACK, B3) + )); + Rook rook = new Rook(Color.BLACK, B1); + + //when + boolean movable = rook.isMovable(chessBoard, B4); + + //then + assertThat(movable).isFalse(); + } + + private static Stream provideMovablePosition() { + return Stream.of( + Arguments.of(A1, A8), + Arguments.of(B2, H2), + Arguments.of(C3, C1), + Arguments.of(B8, B1), + Arguments.of(B8, B4) + ); + } +} From 5c22cf0fe33b71f6465d9f3e0552fb8a36745531 Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 15:11:43 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20Bishop=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Bishop.java | 21 ++++++++ src/main/java/chess/piece/King.java | 3 +- src/test/java/chess/piece/BishopTest.java | 58 +++++++++++++++++++++++ src/test/java/chess/piece/KingTest.java | 8 +++- 4 files changed, 87 insertions(+), 3 deletions(-) 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 341502772d..81ad13a064 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -2,16 +2,37 @@ import chess.ChessBoard; import chess.Color; +import chess.Movement; import chess.Position; +import java.util.List; public class Bishop extends Piece { + private static final List MOVEMENTS = List.of( + Movement.LEFT_UP, Movement.LEFT_DOWN, Movement.RIGHT_UP, Movement.RIGHT_DOWN + ); + public Bishop(Color color, Position position) { super(color, position); } @Override boolean isMovable(ChessBoard chessBoard, Position to) { + for (Movement movement : MOVEMENTS) { + Position curr = position; + while (!curr.equals(to)) { + if (!curr.canMove(movement)) { + break; + } + curr = curr.move(movement); + if (chessBoard.isExistPiece(curr)) { + break; + } + } + if (curr.equals(to)) { + return true; + } + } return false; } } diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index de19481009..8ac7b4a22e 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -9,7 +9,8 @@ public class King extends Piece { private static final Set MOVEMENTS = Set.of( - Movement.UP, Movement.DOWN, Movement.LEFT, Movement.RIGHT + Movement.UP, Movement.DOWN, Movement.LEFT, Movement.RIGHT, + Movement.LEFT_UP, Movement.LEFT_DOWN, Movement.RIGHT_UP, Movement.RIGHT_DOWN ); public King(Color color, Position position) { diff --git a/src/test/java/chess/piece/BishopTest.java b/src/test/java/chess/piece/BishopTest.java new file mode 100644 index 0000000000..9735641757 --- /dev/null +++ b/src/test/java/chess/piece/BishopTest.java @@ -0,0 +1,58 @@ +package chess.piece; + +import static chess.Fixtures.B1; +import static chess.Fixtures.C2; +import static chess.Fixtures.D3; +import static org.assertj.core.api.Assertions.assertThat; + +import chess.ChessBoard; +import chess.Color; +import chess.Fixtures; +import chess.Position; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class BishopTest { + + @ParameterizedTest + @MethodSource("provideMovablePosition") + void 비숍은_대각선으로_보드판_끝까지_갈_수_있다(Position from, Position to) { + //given + ChessBoard chessBoard = new ChessBoard(List.of()); + Bishop bishop = new Bishop(Color.BLACK, from); + + //when + boolean movable = bishop.isMovable(chessBoard, to); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 비숍이_기는_방향에_기물이_있다면_갈_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Pawn(Color.BLACK, C2) + )); + Bishop bishop = new Bishop(Color.BLACK, B1); + + //when + boolean movable = bishop.isMovable(chessBoard, D3); + + //then + assertThat(movable).isFalse(); + } + + private static Stream provideMovablePosition() { + return Stream.of( + Arguments.of(Fixtures.A1, Fixtures.H8), + Arguments.of(Fixtures.B2, Fixtures.A3), + Arguments.of(Fixtures.D2, Fixtures.C1), + Arguments.of(Fixtures.E7, Fixtures.F6) + ); + } +} diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java index ddd8290feb..84008f9dcf 100644 --- a/src/test/java/chess/piece/KingTest.java +++ b/src/test/java/chess/piece/KingTest.java @@ -18,7 +18,7 @@ class KingTest { @ParameterizedTest @MethodSource("provideMovablePosition") - void 킹은_상_하_좌_우_한칸_같은팀의_기물이_없다면_이동할_수_있다(Position from, Position to) { + void 킹은_상_하_좌_우_대각선_한칸_같은팀의_기물이_없다면_이동할_수_있다(Position from, Position to) { //given ChessBoard chessBoard = new ChessBoard(List.of()); King king = new King(Color.BLACK, from); @@ -48,7 +48,11 @@ private static Stream provideMovablePosition() { Arguments.of(Fixtures.A1, Fixtures.A2), Arguments.of(Fixtures.B2, Fixtures.B1), Arguments.of(Fixtures.B1, Fixtures.C1), - Arguments.of(Fixtures.C2, Fixtures.B2) + Arguments.of(Fixtures.C2, Fixtures.B2), + Arguments.of(Fixtures.C2, Fixtures.D3), + Arguments.of(Fixtures.C2, Fixtures.B2), + Arguments.of(Fixtures.C2, Fixtures.B1), + Arguments.of(Fixtures.C2, Fixtures.D1) ); } } From 3f11e76c09262c814cd207f4d2d571ca9bdce369 Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 15:14:20 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20Queen=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Queen.java | 22 ++++++++ src/test/java/chess/piece/QueenTest.java | 71 ++++++++++++++++++++++++ 2 files changed, 93 insertions(+) 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 2074a1a1dc..a6a4aa0bb3 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -2,16 +2,38 @@ import chess.ChessBoard; import chess.Color; +import chess.Movement; import chess.Position; +import java.util.Set; public class Queen extends Piece { + private static final Set MOVEMENTS = Set.of( + Movement.UP, Movement.DOWN, Movement.LEFT, Movement.RIGHT, + Movement.LEFT_UP, Movement.LEFT_DOWN, Movement.RIGHT_UP, Movement.RIGHT_DOWN + ); + public Queen(Color color, Position position) { super(color, position); } @Override boolean isMovable(ChessBoard chessBoard, Position to) { + for (Movement movement : MOVEMENTS) { + Position curr = position; + while (!curr.equals(to)) { + if (!curr.canMove(movement)) { + break; + } + curr = curr.move(movement); + if (chessBoard.isExistPiece(curr)) { + break; + } + } + if (curr.equals(to)) { + return true; + } + } return false; } } diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java new file mode 100644 index 0000000000..cec68d813c --- /dev/null +++ b/src/test/java/chess/piece/QueenTest.java @@ -0,0 +1,71 @@ +package chess.piece; + +import static chess.Fixtures.A1; +import static chess.Fixtures.A8; +import static chess.Fixtures.B1; +import static chess.Fixtures.B2; +import static chess.Fixtures.B4; +import static chess.Fixtures.B8; +import static chess.Fixtures.C1; +import static chess.Fixtures.C2; +import static chess.Fixtures.C3; +import static chess.Fixtures.D3; +import static chess.Fixtures.H2; +import static org.assertj.core.api.Assertions.assertThat; + +import chess.ChessBoard; +import chess.Color; +import chess.Fixtures; +import chess.Position; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class QueenTest { + + @ParameterizedTest + @MethodSource("provideMovablePosition") + void 퀸은_상하좌우_또는_대각선으로_보드판_끝까지_갈_수_있다(Position from, Position to) { + //given + ChessBoard chessBoard = new ChessBoard(List.of()); + Queen queen = new Queen(Color.BLACK, from); + + //when + boolean movable = queen.isMovable(chessBoard, to); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 퀸이_기는_방향에_기물이_있다면_갈_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Pawn(Color.BLACK, C2) + )); + Queen queen = new Queen(Color.BLACK, B1); + + //when + boolean movable = queen.isMovable(chessBoard, D3); + + //then + assertThat(movable).isFalse(); + } + + private static Stream provideMovablePosition() { + return Stream.of( + Arguments.of(Fixtures.A1, Fixtures.H8), + Arguments.of(Fixtures.B2, Fixtures.A3), + Arguments.of(Fixtures.D2, Fixtures.C1), + Arguments.of(Fixtures.E7, Fixtures.F6), + Arguments.of(A1, A8), + Arguments.of(B2, H2), + Arguments.of(C3, C1), + Arguments.of(B8, B1), + Arguments.of(B8, B4) + ); + } +} From dba144b1a46ffad1184a330263bbabf67a788726 Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 15:17:30 +0900 Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20movable=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=A0=9C=EC=96=B4=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/piece/Bishop.java | 2 +- src/main/java/chess/piece/Knight.java | 2 +- src/main/java/chess/piece/Pawn.java | 3 ++- src/main/java/chess/piece/Piece.java | 2 +- src/main/java/chess/piece/Queen.java | 2 +- src/main/java/chess/piece/Rook.java | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 81ad13a064..2a7c96e246 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -17,7 +17,7 @@ public Bishop(Color color, Position position) { } @Override - boolean isMovable(ChessBoard chessBoard, Position to) { + protected boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; while (!curr.equals(to)) { diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index ad1516473a..6e8b671d4e 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -20,7 +20,7 @@ public Knight(Color color, Position position) { } @Override - boolean isMovable(ChessBoard chessBoard, Position to) { + protected boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; if (!curr.canMove(movement)) { diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 7208b62a19..42d4c52257 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -6,12 +6,13 @@ public class Pawn extends Piece { + public Pawn(Color color, Position position) { super(color, position); } @Override - boolean isMovable(ChessBoard chessBoard, Position to) { + protected boolean isMovable(ChessBoard chessBoard, Position to) { return false; } } diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java index 036e38100f..fb44803e72 100644 --- a/src/main/java/chess/piece/Piece.java +++ b/src/main/java/chess/piece/Piece.java @@ -38,7 +38,7 @@ public boolean isPosition(Position position) { return this.position.equals(position); } - abstract boolean isMovable(ChessBoard chessBoard, Position to); + abstract protected boolean isMovable(ChessBoard chessBoard, Position to); @Override public boolean equals(Object object) { diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index a6a4aa0bb3..5898afaf57 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -18,7 +18,7 @@ public Queen(Color color, Position position) { } @Override - boolean isMovable(ChessBoard chessBoard, Position to) { + protected boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; while (!curr.equals(to)) { diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 0dfe68e59d..7bd13a6c2a 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -17,7 +17,7 @@ public Rook(Color color, Position position) { } @Override - boolean isMovable(ChessBoard chessBoard, Position to) { + protected boolean isMovable(ChessBoard chessBoard, Position to) { for (Movement movement : MOVEMENTS) { Position curr = position; while (!curr.equals(to)) { From 09989516a639e3065388410d3766118da2d8ca0a Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 16:22:26 +0900 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=ED=8F=B0=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/Position.java | 4 + src/main/java/chess/piece/BlackPawn.java | 37 ++++++++ src/main/java/chess/piece/Pawn.java | 46 +++++++++- src/main/java/chess/piece/WhitePawn.java | 37 ++++++++ src/test/java/chess/piece/BishopTest.java | 2 +- src/test/java/chess/piece/BlackPawnTest.java | 85 ++++++++++++++++++ src/test/java/chess/piece/KnightTest.java | 2 +- src/test/java/chess/piece/QueenTest.java | 2 +- src/test/java/chess/piece/RookTest.java | 3 +- src/test/java/chess/piece/WhitePawnTest.java | 91 ++++++++++++++++++++ 10 files changed, 300 insertions(+), 9 deletions(-) create mode 100644 src/main/java/chess/piece/BlackPawn.java create mode 100644 src/main/java/chess/piece/WhitePawn.java create mode 100644 src/test/java/chess/piece/BlackPawnTest.java create mode 100644 src/test/java/chess/piece/WhitePawnTest.java diff --git a/src/main/java/chess/Position.java b/src/main/java/chess/Position.java index 3ebeb0ea18..cfcd9630a3 100644 --- a/src/main/java/chess/Position.java +++ b/src/main/java/chess/Position.java @@ -167,4 +167,8 @@ public Position moveHorizontal(final int step) { } return this; } + + public boolean isRow(Row row) { + return this.row == row; + } } diff --git a/src/main/java/chess/piece/BlackPawn.java b/src/main/java/chess/piece/BlackPawn.java new file mode 100644 index 0000000000..5f14d65a0f --- /dev/null +++ b/src/main/java/chess/piece/BlackPawn.java @@ -0,0 +1,37 @@ +package chess.piece; + +import chess.ChessBoard; +import chess.Color; +import chess.Movement; +import chess.Position; +import chess.Row; +import java.util.Set; + +public class BlackPawn extends Pawn { + + private static final Row INITINAL_ROW = Row.SEVEN; + + public BlackPawn(Position position) { + super(Color.BLACK, position); + } + + @Override + protected boolean isAttack(ChessBoard chessBoard, Position to) { + return chessBoard.isColorInPosition(Color.WHITE, to); + } + + @Override + protected boolean isFirstMovement() { + return position.isRow(INITINAL_ROW); + } + + @Override + protected Set attackMovements() { + return Set.of(Movement.LEFT_DOWN, Movement.RIGHT_DOWN); + } + + @Override + protected Movement movement() { + return Movement.DOWN; + } +} diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 42d4c52257..3a62b37219 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -2,17 +2,55 @@ import chess.ChessBoard; import chess.Color; +import chess.Movement; import chess.Position; +import java.util.Set; -public class Pawn extends Piece { - +public abstract class Pawn extends Piece { public Pawn(Color color, Position position) { super(color, position); } - @Override protected boolean isMovable(ChessBoard chessBoard, Position to) { - return false; + if (isAttack(chessBoard, to)) { + for (Movement movement : attackMovements()) { + Position curr = position; + if (!curr.canMove(movement)) { + continue; + } + curr = curr.move(movement); + if (curr.equals(to)) { + return true; + } + } + return false; + } + if (chessBoard.isExistPiece(to)) { + return false; + } + if (isFirstMovement()) { + Position curr = position; + for (int cnt = 0; cnt < 2; cnt++) { + if (!curr.canMove(movement())) { + break; + } + curr = curr.move(movement()); + if (chessBoard.isExistPiece(curr)) { + break; + } + } + return curr.equals(to); + } + return position.canMove(movement()) && + position.move(movement()).equals(to); } + + abstract protected boolean isAttack(ChessBoard chessBoard, Position to); + + abstract protected boolean isFirstMovement(); + + abstract protected Set attackMovements(); + + abstract protected Movement movement(); } diff --git a/src/main/java/chess/piece/WhitePawn.java b/src/main/java/chess/piece/WhitePawn.java new file mode 100644 index 0000000000..0e0213f2a5 --- /dev/null +++ b/src/main/java/chess/piece/WhitePawn.java @@ -0,0 +1,37 @@ +package chess.piece; + +import chess.ChessBoard; +import chess.Color; +import chess.Movement; +import chess.Position; +import chess.Row; +import java.util.Set; + +public class WhitePawn extends Pawn { + + private static final Row INITINAL_ROW = Row.TWO; + + public WhitePawn(Position position) { + super(Color.WHITE, position); + } + + @Override + protected boolean isAttack(ChessBoard chessBoard, Position to) { + return chessBoard.isColorInPosition(Color.BLACK, to); + } + + @Override + protected boolean isFirstMovement() { + return position.isRow(INITINAL_ROW); + } + + @Override + protected Set attackMovements() { + return Set.of(Movement.LEFT_UP, Movement.RIGHT_UP); + } + + @Override + protected Movement movement() { + return Movement.UP; + } +} diff --git a/src/test/java/chess/piece/BishopTest.java b/src/test/java/chess/piece/BishopTest.java index 9735641757..3982bffb52 100644 --- a/src/test/java/chess/piece/BishopTest.java +++ b/src/test/java/chess/piece/BishopTest.java @@ -36,7 +36,7 @@ class BishopTest { void 비숍이_기는_방향에_기물이_있다면_갈_수_없다() { //given ChessBoard chessBoard = new ChessBoard(List.of( - new Pawn(Color.BLACK, C2) + new BlackPawn(C2) )); Bishop bishop = new Bishop(Color.BLACK, B1); diff --git a/src/test/java/chess/piece/BlackPawnTest.java b/src/test/java/chess/piece/BlackPawnTest.java new file mode 100644 index 0000000000..d440f826c5 --- /dev/null +++ b/src/test/java/chess/piece/BlackPawnTest.java @@ -0,0 +1,85 @@ +package chess.piece; + +import static chess.Fixtures.B5; +import static chess.Fixtures.D4; +import static chess.Fixtures.H4; +import static chess.Fixtures.H5; +import static org.assertj.core.api.Assertions.assertThat; + +import chess.ChessBoard; +import chess.Color; +import chess.Fixtures; +import java.util.List; +import org.junit.jupiter.api.Test; + +class BlackPawnTest { + + @Test + void 블랙_폰은_아래로_한칸_이동할_수_있다() { + //given + BlackPawn blackPawn = new BlackPawn(H5); + + //when + boolean movable = blackPawn.isMovable(new ChessBoard(List.of()), H4); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 블랙_폰은_초기에_아래로_두칸_이동할_수_있다() { + //given + BlackPawn blackPawn = new BlackPawn(Fixtures.H7); + + //when + boolean movable = blackPawn.isMovable(new ChessBoard(List.of()), H5); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 블랙_폰은_아래_대각선에_상대_기물이_있다면_대각선으로_이동할_수_있다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Rook(Color.WHITE, Fixtures.D4) + )); + BlackPawn blackPawn = new BlackPawn(Fixtures.E5); + + //when + boolean movable = blackPawn.isMovable(chessBoard, D4); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 블랙_폰은_공격이_아닌_이동일때_목적지까지_가는데_기물이_있다면_이동할_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Rook(Color.WHITE, Fixtures.B6) + )); + BlackPawn blackPawn = new BlackPawn(Fixtures.B7); + + //when + boolean movable = blackPawn.isMovable(chessBoard, B5); + + //then + assertThat(movable).isFalse(); + } + + @Test + void 블랙_폰은_공격이_아닌_이동일때_목적지에_기물이_있다면_이동할_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Rook(Color.WHITE, Fixtures.B5) + )); + BlackPawn blackPawn = new BlackPawn(Fixtures.B6); + + //when + boolean movable = blackPawn.isMovable(chessBoard, B5); + + //then + assertThat(movable).isFalse(); + } +} diff --git a/src/test/java/chess/piece/KnightTest.java b/src/test/java/chess/piece/KnightTest.java index 0877952771..7ec44a62c7 100644 --- a/src/test/java/chess/piece/KnightTest.java +++ b/src/test/java/chess/piece/KnightTest.java @@ -38,7 +38,7 @@ class KnightTest { void 나이트가_가는방향에_기물이_있더라도_갈_수_있다() { //given ChessBoard chessBoard = new ChessBoard(List.of( - new Pawn(Color.BLACK, B1) + new BlackPawn(C2) )); Knight knight = new Knight(Color.BLACK, A1); diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java index cec68d813c..e208ee990b 100644 --- a/src/test/java/chess/piece/QueenTest.java +++ b/src/test/java/chess/piece/QueenTest.java @@ -44,7 +44,7 @@ class QueenTest { void 퀸이_기는_방향에_기물이_있다면_갈_수_없다() { //given ChessBoard chessBoard = new ChessBoard(List.of( - new Pawn(Color.BLACK, C2) + new BlackPawn(C2) )); Queen queen = new Queen(Color.BLACK, B1); diff --git a/src/test/java/chess/piece/RookTest.java b/src/test/java/chess/piece/RookTest.java index 5ae97bd3a3..e3d9ec4e96 100644 --- a/src/test/java/chess/piece/RookTest.java +++ b/src/test/java/chess/piece/RookTest.java @@ -4,7 +4,6 @@ import static chess.Fixtures.A8; import static chess.Fixtures.B1; import static chess.Fixtures.B2; -import static chess.Fixtures.B3; import static chess.Fixtures.B4; import static chess.Fixtures.B8; import static chess.Fixtures.C1; @@ -42,7 +41,7 @@ class RookTest { void 룩이_기는_방향에_기물이_있다면_갈_수_없다() { //given ChessBoard chessBoard = new ChessBoard(List.of( - new Pawn(Color.BLACK, B3) + new BlackPawn(B2) )); Rook rook = new Rook(Color.BLACK, B1); diff --git a/src/test/java/chess/piece/WhitePawnTest.java b/src/test/java/chess/piece/WhitePawnTest.java new file mode 100644 index 0000000000..a462a55bcf --- /dev/null +++ b/src/test/java/chess/piece/WhitePawnTest.java @@ -0,0 +1,91 @@ +package chess.piece; + +import static chess.Fixtures.B2; +import static chess.Fixtures.B3; +import static chess.Fixtures.B4; +import static chess.Fixtures.B6; +import static chess.Fixtures.B7; +import static chess.Fixtures.D6; +import static chess.Fixtures.E5; +import static chess.Fixtures.H2; +import static chess.Fixtures.H4; +import static chess.Fixtures.H5; +import static chess.Fixtures.H6; +import static org.assertj.core.api.Assertions.assertThat; + +import chess.ChessBoard; +import chess.Color; +import java.util.List; +import org.junit.jupiter.api.Test; + +class WhitePawnTest { + + @Test + void 화이트_폰은_아래로_한칸_이동할_수_있다() { + //given + WhitePawn whitePawn = new WhitePawn(H5); + + //when + boolean movable = whitePawn.isMovable(new ChessBoard(List.of()), H6); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 화이트_폰은_초기에_아래로_두칸_이동할_수_있다() { + //given + WhitePawn whitePawn = new WhitePawn(H2); + + //when + boolean movable = whitePawn.isMovable(new ChessBoard(List.of()), H4); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 화이트_폰은_아래_대각선에_상대_기물이_있다면_대각선으로_이동할_수_있다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Rook(Color.BLACK, D6) + )); + WhitePawn whitePawn = new WhitePawn(E5); + + //when + boolean movable = whitePawn.isMovable(chessBoard, D6); + + //then + assertThat(movable).isTrue(); + } + + @Test + void 화이트_폰은_공격이_아닌_이동일때_목적지까지_가는데_기물이_있다면_이동할_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Rook(Color.WHITE, B3) + )); + WhitePawn whitePawn = new WhitePawn(B2); + + //when + boolean movable = whitePawn.isMovable(chessBoard, B4); + + //then + assertThat(movable).isFalse(); + } + + @Test + void 화이트_폰은_공격이_아닌_이동일때_목적지에_기물이_있다면_이동할_수_없다() { + //given + ChessBoard chessBoard = new ChessBoard(List.of( + new Rook(Color.WHITE, B7) + )); + WhitePawn whitePawn = new WhitePawn(B6); + + //when + boolean movable = whitePawn.isMovable(chessBoard, B7); + + //then + assertThat(movable).isFalse(); + } +} From 1f0c9d157ea872a5ba84d2c467137800f16164ef Mon Sep 17 00:00:00 2001 From: LeeJaeHoon Date: Sat, 22 Mar 2025 17:17:19 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EB=B7=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/chess/ChessBoard.java | 63 ++++++++++++++++++++++- src/main/java/chess/ChessGame.java | 65 ++++++++++++++++++++++++ src/main/java/chess/Color.java | 1 + src/main/java/chess/Row.java | 35 ++++++++++--- src/main/java/chess/piece/Bishop.java | 8 +++ src/main/java/chess/piece/BlackPawn.java | 5 ++ src/main/java/chess/piece/King.java | 8 +++ src/main/java/chess/piece/Knight.java | 8 +++ src/main/java/chess/piece/Pawn.java | 3 ++ src/main/java/chess/piece/Piece.java | 5 +- src/main/java/chess/piece/Queen.java | 8 +++ src/main/java/chess/piece/Rook.java | 8 +++ src/main/java/chess/piece/WhitePawn.java | 5 ++ 13 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 src/main/java/chess/ChessGame.java diff --git a/src/main/java/chess/ChessBoard.java b/src/main/java/chess/ChessBoard.java index 8e703c5c36..8e821dd02c 100644 --- a/src/main/java/chess/ChessBoard.java +++ b/src/main/java/chess/ChessBoard.java @@ -1,16 +1,65 @@ package chess; +import chess.piece.Bishop; +import chess.piece.BlackPawn; +import chess.piece.King; +import chess.piece.Knight; import chess.piece.Piece; +import chess.piece.Queen; +import chess.piece.Rook; +import chess.piece.WhitePawn; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class ChessBoard { - private final List pieces; + private static final List INITIAL_PIECES = List.of( + new Rook(Color.BLACK, new Position(Column.A, Row.EIGHT)), + new Knight(Color.BLACK, new Position(Column.B, Row.EIGHT)), + new Bishop(Color.BLACK, new Position(Column.C, Row.EIGHT)), + new Queen(Color.BLACK, new Position(Column.D, Row.EIGHT)), + new King(Color.BLACK, new Position(Column.E, Row.EIGHT)), + new Bishop(Color.BLACK, new Position(Column.F, Row.EIGHT)), + new Knight(Color.BLACK, new Position(Column.G, Row.EIGHT)), + new Rook(Color.BLACK, new Position(Column.H, Row.EIGHT)), + new BlackPawn(new Position(Column.A, Row.SEVEN)), + new BlackPawn(new Position(Column.B, Row.SEVEN)), + new BlackPawn(new Position(Column.C, Row.SEVEN)), + new BlackPawn(new Position(Column.D, Row.SEVEN)), + new BlackPawn(new Position(Column.E, Row.SEVEN)), + new BlackPawn(new Position(Column.F, Row.SEVEN)), + new BlackPawn(new Position(Column.G, Row.SEVEN)), + new BlackPawn(new Position(Column.H, Row.SEVEN)), + + new Rook(Color.WHITE, new Position(Column.A, Row.ONE)), + new Knight(Color.WHITE, new Position(Column.B, Row.ONE)), + new Bishop(Color.WHITE, new Position(Column.C, Row.ONE)), + new Queen(Color.WHITE, new Position(Column.D, Row.ONE)), + new King(Color.WHITE, new Position(Column.E, Row.ONE)), + new Bishop(Color.WHITE, new Position(Column.F, Row.ONE)), + new Knight(Color.WHITE, new Position(Column.G, Row.ONE)), + new Rook(Color.WHITE, new Position(Column.H, Row.ONE)), + new WhitePawn(new Position(Column.A, Row.TWO)), + new WhitePawn(new Position(Column.B, Row.TWO)), + new WhitePawn(new Position(Column.C, Row.TWO)), + new WhitePawn(new Position(Column.D, Row.TWO)), + new WhitePawn(new Position(Column.E, Row.TWO)), + new WhitePawn(new Position(Column.F, Row.TWO)), + new WhitePawn(new Position(Column.G, Row.TWO)), + new WhitePawn(new Position(Column.H, Row.TWO)) + ); + + private List pieces; public ChessBoard(List pieces) { this.pieces = pieces; } - + + public static ChessBoard initialize() { + return new ChessBoard(new ArrayList<>(INITIAL_PIECES)); + } + public void move(Color color, Position from, Position to) { if (isNotExistPiece(from)) { throw new IllegalArgumentException("출발지에 기물이 없습니다."); @@ -40,4 +89,14 @@ public Piece findPiece(Position position) { .findFirst() .orElse(null); } + + public List getPieces() { + return Collections.unmodifiableList(pieces); + } + + public void remove(Position position) { + pieces = pieces.stream() + .filter(piece -> !piece.isPosition(position)) + .toList(); + } } diff --git a/src/main/java/chess/ChessGame.java b/src/main/java/chess/ChessGame.java new file mode 100644 index 0000000000..5c41f8d974 --- /dev/null +++ b/src/main/java/chess/ChessGame.java @@ -0,0 +1,65 @@ +package chess; + +import chess.piece.Piece; +import java.util.Scanner; + +public class ChessGame { + + private static final Scanner scanner = new Scanner(System.in); + private static final Color START_COLOR = Color.WHITE; + + public static void main(String[] args) { + ChessGame chessGame = new ChessGame(); + chessGame.play(); + } + + public void play() { + System.out.println("게임을 시작합니다."); + ChessBoard chessBoard = ChessBoard.initialize(); + printChessBoard(chessBoard); + + Color currentTurnColor = START_COLOR; + while (true) { + System.out.println(currentTurnColor + "의 차례입니다. 기물을 이동하세요 ex) a1 a2"); + + String[] commands = readLine().split(" "); + Position from = toPosition(commands[0]); + Position to = toPosition(commands[1]); + chessBoard.move(currentTurnColor, from, to); + printChessBoard(chessBoard); + currentTurnColor = currentTurnColor.opposite(); + } + } + + private void printChessBoard(ChessBoard chessBoard) { + StringBuilder sb = new StringBuilder(); + for (int rowSymbol = 8; rowSymbol > 0; rowSymbol--) { + Row row = Row.fromSymbol(rowSymbol); + sb.append(row.getSymbol()).append(" "); + for (char col = 'A'; col <= 'H'; col++) { + Column column = Column.valueOf(col + ""); + Position position = new Position(row, column); + Piece piece = chessBoard.findPiece(position); + if (piece == null) { + sb.append(". "); + continue; + } + sb.append(piece).append(" "); + } + sb.append("\n"); + } + sb.append(" ").append("a b c d e f g h"); + + System.out.println(sb); + } + + private String readLine() { + return scanner.nextLine().trim(); + } + + private Position toPosition(String command) { + Column column = Column.valueOf(Character.toString(command.charAt(0)).toUpperCase()); + Row row = Row.fromSymbol(command.charAt(1) - '0'); + return new Position(column, row); + } +} diff --git a/src/main/java/chess/Color.java b/src/main/java/chess/Color.java index 55cd020b68..03d6e45e9e 100644 --- a/src/main/java/chess/Color.java +++ b/src/main/java/chess/Color.java @@ -6,6 +6,7 @@ public enum Color { WHITE, EMPTY; + public boolean isWhite() { return this == WHITE; } diff --git a/src/main/java/chess/Row.java b/src/main/java/chess/Row.java index 126ed048da..391a948c4d 100644 --- a/src/main/java/chess/Row.java +++ b/src/main/java/chess/Row.java @@ -1,15 +1,30 @@ package chess; +import java.util.Arrays; + public enum Row { - EIGHT, - SEVEN, - SIX, - FIVE, - FOUR, - THREE, - TWO, - ONE; + EIGHT(8), + SEVEN(7), + SIX(6), + FIVE(5), + FOUR(4), + THREE(3), + TWO(2), + ONE(1); + + private final int symbol; + + Row(int symbol) { + this.symbol = symbol; + } + + public static Row fromSymbol(int symbol) { + return Arrays.stream(values()) + .filter(row -> row.symbol == symbol) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + } public boolean isTop() { return ordinal() == 0; @@ -50,4 +65,8 @@ public Row moveDown(final int step) { throw new IllegalStateException("움직일 수 없는 위치입니다."); } + + public int getSymbol() { + return symbol; + } } diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java index 2a7c96e246..93bcfcf975 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -35,4 +35,12 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { } return false; } + + @Override + public String toString() { + if (isColor(Color.BLACK)) { + return "b"; + } + return "B"; + } } diff --git a/src/main/java/chess/piece/BlackPawn.java b/src/main/java/chess/piece/BlackPawn.java index 5f14d65a0f..83b5da19e8 100644 --- a/src/main/java/chess/piece/BlackPawn.java +++ b/src/main/java/chess/piece/BlackPawn.java @@ -34,4 +34,9 @@ protected Set attackMovements() { protected Movement movement() { return Movement.DOWN; } + + @Override + public String toString() { + return "p"; + } } diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index 8ac7b4a22e..bcd3ca342a 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -31,4 +31,12 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { } return false; } + + @Override + public String toString() { + if (isColor(Color.BLACK)) { + return "k"; + } + return "K"; + } } diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 6e8b671d4e..8adfa62e07 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -33,4 +33,12 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { } return false; } + + @Override + public String toString() { + if (isColor(Color.BLACK)) { + return "n"; + } + return "N"; + } } diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index 3a62b37219..a135651083 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -39,6 +39,9 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { if (chessBoard.isExistPiece(curr)) { break; } + if (curr.equals(to)) { + return true; + } } return curr.equals(to); } diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java index fb44803e72..262e255b0b 100644 --- a/src/main/java/chess/piece/Piece.java +++ b/src/main/java/chess/piece/Piece.java @@ -25,11 +25,12 @@ public void move(ChessBoard chessBoard, Color color, Position to) { if (!isMovable(chessBoard, to)) { throw new IllegalArgumentException("해당 목적지로 갈 수 없습니다."); } + if (chessBoard.isExistPiece(to)) { + chessBoard.remove(to); + } position = to; } - ; - public boolean isColor(Color color) { return this.color == color; } diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 5898afaf57..d814a37ea1 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -36,4 +36,12 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { } return false; } + + @Override + public String toString() { + if (isColor(Color.BLACK)) { + return "q"; + } + return "Q"; + } } diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 7bd13a6c2a..6d93243459 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -35,4 +35,12 @@ protected boolean isMovable(ChessBoard chessBoard, Position to) { } return false; } + + @Override + public String toString() { + if (isColor(Color.BLACK)) { + return "r"; + } + return "R"; + } } diff --git a/src/main/java/chess/piece/WhitePawn.java b/src/main/java/chess/piece/WhitePawn.java index 0e0213f2a5..42f563237a 100644 --- a/src/main/java/chess/piece/WhitePawn.java +++ b/src/main/java/chess/piece/WhitePawn.java @@ -34,4 +34,9 @@ protected Set attackMovements() { protected Movement movement() { return Movement.UP; } + + @Override + public String toString() { + return "P"; + } }