diff --git a/README.md b/README.md index 8102f91c870..3fcac6d00a0 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,42 @@ 체스 미션 저장소 +```text + ABCDEFGH +8 RNBQKBNR +7 PPPPPPPP +6 +5 +4 +3 +2 PPPPPPPP +1 RNBQKBNR +``` + +## 요구사항 +- 킹(King) + - 위, 아래, 양옆, 대각선 한 칸씩 이동 +- 퀸(Queen) + - 일직선으로 앞, 뒤, 옆, 대각선 어떤 방향이든 원하는 만큼 이동 + - 본인의 기물을 뚫고 갈 수 없음(같은 팀) + - 상대방을 잡으면 종료됨 +- 룩(Rook) + - 원하는 만큼 앞, 뒤, 양옆으로 이동 가능 +- 나이트(Knight) + - 한 방향으로 두 칸을 이동하고 그와 90도를 이루는 방향 + - 전진 2칸 + 옆 1칸 + - 왼쪽 2칸 + 위 or 아래 1칸 + - 오른쪽 2칸 + 위 or 아래 1칸 + - 뒤 2칸 + 옆 1칸 + - 유일하게 중간에 기물이 있어도 뛰어넘을 수 있음 +- 비숍(Bishop) + - 원하는 만큼 대각선으로만 이동 가능 + - 한 개의 색깔에서 시작해 그 색으로만 다님 +- 폰(Pawn) + - 앞으로 1칸 + - 잡을 때는 대각선 1칸만 가능 + - 처음 움직이는 폰은 2칸 가능 + ## 우아한테크코스 코드리뷰 - [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java new file mode 100644 index 00000000000..43181ea1085 --- /dev/null +++ b/src/main/java/chess/Application.java @@ -0,0 +1,32 @@ +package chess; + +import chess.view.InputView; +import chess.view.ResultView; + +public class Application { + + public static void main(String[] args) { + InputView inputView = new InputView(); + ResultView resultView = new ResultView(); + Board board = new Board(); + resultView.printBoard(board); + + while (true) { + String movement = inputView.readMovement(); + if (movement.equals("exit")) { + break; + } + String[] tokens = movement.split(" "); + String[] tokens1 = tokens[0].split(","); + String[] tokens2 = tokens[1].split(","); + Position start = new Position(Row.of(tokens1[1]), Column.valueOf(tokens1[0])); + Position destination = new Position(Row.of(tokens2[1]), Column.valueOf(tokens2[0])); + System.out.println("start = " + start); + System.out.println("destination = " + destination); + board.move(start, destination); + + resultView.printBoard(board); + } + } + +} diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java new file mode 100644 index 00000000000..3076faa55f2 --- /dev/null +++ b/src/main/java/chess/Board.java @@ -0,0 +1,110 @@ +package chess; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +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 chess.piece.Team; + +public class Board { + + private final Map board; + + public Board() { + this.board = new HashMap<>(); + addPawn(); + addFirstLine(); + } + + private void addFirstLine() { + for (Column value : Column.values()) { + if (value == Column.A || value == Column.H) { + Position teamAPosition = new Position(Row.ONE, value); + Position teamBPosition = new Position(Row.EIGHT, value); + board.put(teamAPosition, new Rook(Team.A, teamAPosition)); + board.put(teamBPosition, new Rook(Team.B, teamBPosition)); + } + if (value == Column.B || value == Column.G) { + Position teamAPosition = new Position(Row.ONE, value); + Position teamBPosition = new Position(Row.EIGHT, value); + board.put(teamAPosition, new Knight(Team.A, teamAPosition)); + board.put(teamBPosition, new Knight(Team.B, teamBPosition)); + } + if (value == Column.C || value == Column.F) { + Position teamAPosition = new Position(Row.ONE, value); + Position teamBPosition = new Position(Row.EIGHT, value); + board.put(teamAPosition, new Bishop(Team.A, teamAPosition)); + board.put(teamBPosition, new Bishop(Team.B, teamBPosition)); + } + if (value == Column.D) { + Position teamAPosition = new Position(Row.ONE, value); + Position teamBPosition = new Position(Row.EIGHT, value); + board.put(teamAPosition, new Queen(Team.A, teamAPosition)); + board.put(teamBPosition, new Queen(Team.B, teamBPosition)); + } + if (value == Column.E) { + Position teamAPosition = new Position(Row.ONE, value); + Position teamBPosition = new Position(Row.EIGHT, value); + board.put(teamAPosition, new King(Team.A, teamAPosition)); + board.put(teamBPosition, new King(Team.B, teamBPosition)); + } + } + } + + private void addPawn() { + for (Column column : Column.values()) { + Position teamAPosition = new Position(Row.TWO, column); + Position teamBPosition = new Position(Row.SEVEN, column); + board.put(teamAPosition, new Pawn(Team.A, teamAPosition)); + board.put(teamBPosition, new Pawn(Team.B, teamBPosition)); + } + } + + public Piece findByPosition(final Position position) { + if (board.containsKey(position)) { + return board.get(position); + } + throw new IllegalArgumentException("해당 위치에 기물이 존재하지 않습니다."); + } + + public void move(final Position start, final Position destination) { + if (!board.containsKey(start)) { + throw new IllegalArgumentException("해당 위치에 기물이 존재하지 않습니다."); + } + int rowDiff = Row.calculateDiff(start.row(), destination.row()); + int columnDiff = Column.calculateDiff(start.column(), destination.column()); + + Map movements = Movement.calculate(rowDiff, columnDiff); + if (movements.isEmpty()) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + + Piece piece = board.get(start); + if (board.containsKey(destination)) { + Piece otherPiece = board.get(destination); + if (piece.isSameTeam(otherPiece)) { + throw new IllegalArgumentException("해당 위치로 움직일 수 없습니다."); + } + } + for (Entry entry : movements.entrySet()) { + for (int i = 0; i < entry.getValue(); i++) { + piece = piece.move(entry.getKey()); + } + } + board.remove(start); + board.put(destination, piece); + + } + + public Map getBoard() { + return board; + } + +} diff --git a/src/main/java/chess/Column.java b/src/main/java/chess/Column.java index b64b4dc77a3..deda1546390 100644 --- a/src/main/java/chess/Column.java +++ b/src/main/java/chess/Column.java @@ -11,6 +11,10 @@ public enum Column { G, H; + public static int calculateDiff(Column column, Column otherColumn) { + return otherColumn.ordinal() - column.ordinal(); + } + public boolean isFarLeft() { return ordinal() == 0; } diff --git a/src/main/java/chess/Movement.java b/src/main/java/chess/Movement.java index e57c6e91bb9..1598152b379 100644 --- a/src/main/java/chess/Movement.java +++ b/src/main/java/chess/Movement.java @@ -1,5 +1,9 @@ package chess; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public enum Movement { UP(0, 1), UP_UP(UP.x * 2, UP.y * 2), @@ -30,6 +34,25 @@ public enum Movement { this.y = y; } + public static Map calculate(final int rowDiff, final int columnDiff) { + int row = rowDiff; + int column = columnDiff; + System.out.println(row + ", " + column); + Map movements = new HashMap<>(); + while (!(row == 0 && column == 0)) { + for (Movement value : values()) { + if (value.y == row && value.x == column) { + movements.put(value, movements.getOrDefault(value, 0) + 1); + System.out.println(value.name()); + row -= row; + column -= column; + } + } + } + + return movements; + } + public int x() { return x; } @@ -42,6 +65,10 @@ public boolean isVertical() { return x == 0 && y != 0; } + public boolean isHorizontal() { + return x != 0 && y == 0; + } + public boolean isDiagonal() { return x != 0 && y != 0 && Math.abs(x) == Math.abs(y); } diff --git a/src/main/java/chess/Row.java b/src/main/java/chess/Row.java index 126ed048daa..749ab3b54e9 100644 --- a/src/main/java/chess/Row.java +++ b/src/main/java/chess/Row.java @@ -1,15 +1,34 @@ 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 String text; + + Row(final String text) { + this.text = text; + } + + public static Row of(final String text) { + return Arrays.stream(values()) + .filter(value -> value.text.equals(text)) + .findAny() + .orElseThrow(); + } + + public static int calculateDiff(Row row, Row otherRow) { + return Integer.parseInt(otherRow.text) - Integer.parseInt(row.text); + } 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 b14ab70f981..5f2be85a7ce 100644 --- a/src/main/java/chess/piece/Bishop.java +++ b/src/main/java/chess/piece/Bishop.java @@ -1,5 +1,56 @@ package chess.piece; -public class Bishop { +import java.util.Objects; + +import chess.Movement; +import chess.Position; + +public class Bishop extends Piece { + + private final Position position; + + public Bishop(final Team team, final Position position) { + super(team); + this.position = position; + } + + @Override + public Piece move(final Movement movement) { + if (!movement.isDiagonal()) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + if (!position.canMove(movement)) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + try { + return new Bishop(team, position.move(movement)); + } catch (IllegalStateException e) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + } + + @Override + public String getDisplay() { + if (team == Team.A) { + return "b"; + } + return "B"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Bishop bishop)) { + return false; + } + return Objects.equals(position, bishop.position); + } + + @Override + public int hashCode() { + return Objects.hashCode(position); + } } diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java index d64210cad13..f006bd9ef36 100644 --- a/src/main/java/chess/piece/King.java +++ b/src/main/java/chess/piece/King.java @@ -1,5 +1,48 @@ package chess.piece; -public class King { +import java.util.Objects; + +import chess.Movement; +import chess.Position; + +public class King extends Piece { + + private final Position position; + + public King(final Team team, final Position position) { + super(team); + this.position = position; + } + + public King move(final Movement movement) { + if (!movement.isHorizontal() && !movement.isVertical() && !movement.isDiagonal()) { + throw new IllegalArgumentException("이동할 수 없는 위치입니다."); + } + return new King(team, position.move(movement)); + } + + @Override + public String getDisplay() { + if (team == Team.A) { + return "k"; + } + return "K"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof King king)) { + return false; + } + return Objects.equals(position, king.position); + } + + @Override + public int hashCode() { + return Objects.hashCode(position); + } } diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java index 2ee7c47a3bc..66c29178e40 100644 --- a/src/main/java/chess/piece/Knight.java +++ b/src/main/java/chess/piece/Knight.java @@ -1,5 +1,70 @@ package chess.piece; -public class Knight { +import static chess.Movement.DOWN_DOWN_LEFT; +import static chess.Movement.DOWN_DOWN_RIGHT; +import static chess.Movement.LEFT_LEFT_DOWN; +import static chess.Movement.LEFT_LEFT_UP; +import static chess.Movement.RIGHT_RIGHT_DOWN; +import static chess.Movement.RIGHT_RIGHT_UP; +import static chess.Movement.UP_UP_LEFT; +import static chess.Movement.UP_UP_RIGHT; + +import java.util.List; +import java.util.Objects; + +import chess.Movement; +import chess.Position; + +public class Knight extends Piece { + + private static final List MOVEMENTS = List.of( + LEFT_LEFT_UP, LEFT_LEFT_DOWN, RIGHT_RIGHT_UP, RIGHT_RIGHT_DOWN, + UP_UP_LEFT, UP_UP_RIGHT, DOWN_DOWN_LEFT, DOWN_DOWN_RIGHT + ); + + private final Position position; + + public Knight(final Team team, final Position position) { + super(team); + this.position = position; + } + + public Knight move(final Movement movement) { + if (!MOVEMENTS.contains(movement)) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + if (canMove(movement)) { + return new Knight(team, position.move(movement)); + } + throw new IllegalArgumentException("움직일 수 없습니다."); + } + + @Override + public String getDisplay() { + if (team == Team.A) { + return "n"; + } + return "N"; + } + + private boolean canMove(final Movement movement) { + return position.canMoveHorizontal(movement.x()) && position.canMoveVertical(movement.y()); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Knight knight)) { + return false; + } + return Objects.equals(position, knight.position); + } + + @Override + public int hashCode() { + return Objects.hashCode(position); + } } diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java index c8b6cafa51e..b472aea573b 100644 --- a/src/main/java/chess/piece/Pawn.java +++ b/src/main/java/chess/piece/Pawn.java @@ -1,5 +1,63 @@ package chess.piece; -public class Pawn { +import java.util.List; +import java.util.Objects; + +import chess.Movement; +import chess.Position; + +public class Pawn extends Piece { + + private static final List MOVEMENTS = List.of(Movement.UP, Movement.UP_UP, Movement.DOWN, + Movement.DOWN_DOWN); + + private final Position position; + private final boolean hasMoveExperience; + + public Pawn(final Team team, final Position position) { + super(team); + this.position = position; + this.hasMoveExperience = false; + } + + public Pawn(final Team team, final Position position, final boolean hasMoveExperience) { + super(team); + this.position = position; + this.hasMoveExperience = hasMoveExperience; + } + + public Pawn move(final Movement movement) { + if (!MOVEMENTS.contains(movement) || !position.canMove(movement)) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + if (movement.equals(Movement.UP_UP) && hasMoveExperience) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + return new Pawn(team, position.move(movement), true); + } + + @Override + public String getDisplay() { + if (team == Team.A) { + return "p"; + } + return "P"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Pawn pawn)) { + return false; + } + return Objects.equals(position, pawn.position); + } + + @Override + public int hashCode() { + return Objects.hashCode(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..0830fd2ea70 --- /dev/null +++ b/src/main/java/chess/piece/Piece.java @@ -0,0 +1,21 @@ +package chess.piece; + +import chess.Movement; + +public abstract class Piece { + + protected final Team team; + + public Piece(final Team team) { + this.team = team; + } + + public abstract Piece move(final Movement movement); + + public boolean isSameTeam(final Piece otherPiece) { + return this.team.equals(otherPiece.team); + } + + public abstract String getDisplay(); + +} diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java index 9b547261c4b..1d0eb83e86b 100644 --- a/src/main/java/chess/piece/Queen.java +++ b/src/main/java/chess/piece/Queen.java @@ -1,5 +1,52 @@ package chess.piece; -public class Queen { +import java.util.Objects; + +import chess.Movement; +import chess.Position; + +public class Queen extends Piece { + + private final Position position; + + public Queen(final Team team, final Position position) { + super(team); + this.position = position; + } + + @Override + public Piece move(final Movement movement) { + if (!movement.isHorizontal() && !movement.isVertical() && !movement.isDiagonal()) { + throw new IllegalArgumentException("움직일 수 없는 위치입니다."); + } + if (!position.canMove(movement)) { + throw new IllegalArgumentException("해당 위치로 움직일 수 없습니다."); + } + return new Queen(team, position.move(movement)); + } + + @Override + public String getDisplay() { + if (team == Team.A) { + return "q"; + } + return "Q"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Queen queen)) { + return false; + } + return Objects.equals(position, queen.position); + } + + @Override + public int hashCode() { + return Objects.hashCode(position); + } } diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java index 7ed4d08bf03..c50128e0866 100644 --- a/src/main/java/chess/piece/Rook.java +++ b/src/main/java/chess/piece/Rook.java @@ -1,5 +1,52 @@ package chess.piece; -public class Rook { +import java.util.Objects; + +import chess.Movement; +import chess.Position; + +public class Rook extends Piece { + + private final Position position; + + public Rook(Team team, final Position position) { + super(team); + this.position = position; + } + + @Override + public Rook move(final Movement movement) { + if (!movement.isHorizontal() && !movement.isVertical()) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + if (!position.canMove(movement)) { + throw new IllegalArgumentException("움직일 수 없습니다."); + } + return new Rook(team, position.move(movement)); + } + + @Override + public String getDisplay() { + if (team == Team.A) { + return "r"; + } + return "R"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Rook rook)) { + return false; + } + return Objects.equals(position, rook.position); + } + + @Override + public int hashCode() { + return Objects.hashCode(position); + } } diff --git a/src/main/java/chess/piece/Team.java b/src/main/java/chess/piece/Team.java new file mode 100644 index 00000000000..6775657d17c --- /dev/null +++ b/src/main/java/chess/piece/Team.java @@ -0,0 +1,5 @@ +package chess.piece; + +public enum Team { + A,B +} diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java new file mode 100644 index 00000000000..2909a49c6c4 --- /dev/null +++ b/src/main/java/chess/view/InputView.java @@ -0,0 +1,13 @@ +package chess.view; + +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner = new Scanner(System.in); + + public String readMovement() { + System.out.println("음직일 기물의 위치와 목적지를 입력하세요"); + return scanner.nextLine(); + } +} diff --git a/src/main/java/chess/view/ResultView.java b/src/main/java/chess/view/ResultView.java new file mode 100644 index 00000000000..12cf325d34f --- /dev/null +++ b/src/main/java/chess/view/ResultView.java @@ -0,0 +1,52 @@ +package chess.view; + +import java.util.Map; + +import chess.Board; +import chess.Column; +import chess.Position; +import chess.Row; +import chess.piece.Piece; + +public class ResultView { + + Map columns = Map.of( + 1, Column.A, + 2, Column.B, + 3, Column.C, + 4, Column.D, + 5, Column.E, + 6, Column.F, + 7, Column.G, + 8, Column.H + ); + + Map rows = Map.of( + 8, Row.EIGHT, + 7, Row.SEVEN, + 6, Row.SIX, + 5, Row.FIVE, + 4, Row.FOUR, + 3, Row.THREE, + 2, Row.TWO, + 1, Row.ONE + ); + + public void printBoard(final Board board) { + Map getBoard = board.getBoard(); + StringBuilder sb = new StringBuilder(); + for (int i = 1; i <= 8; i++) { + for (int j = 1; j <= 8; j++) { + Position position = new Position(rows.get(Math.abs(i - 9)), columns.get(j)); + if (getBoard.containsKey(position)) { + sb.append(getBoard.get(position).getDisplay()); + } else { + sb.append("."); + } + } + sb.append(System.lineSeparator()); + } + System.out.println(sb); + } + +} diff --git a/src/test/java/chess/BoardTest.java b/src/test/java/chess/BoardTest.java new file mode 100644 index 00000000000..b3fa5113e0a --- /dev/null +++ b/src/test/java/chess/BoardTest.java @@ -0,0 +1,63 @@ +package chess; + +import static chess.Fixtures.*; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +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 chess.piece.Team; + +class BoardTest { + + @MethodSource + @ParameterizedTest + void 체스_보드를_생성하면_2선에_폰만존재한다(Position position) { + Board board = new Board(); + + assertThat(board.findByPosition(position)).isEqualTo(new Pawn(Team.A, position)); + } + + private static Stream 체스_보드를_생성하면_2선에_폰만존재한다() { + return Stream.of( + Arguments.of(A2), Arguments.of(B2), Arguments.of(C2), Arguments.of(D2), + Arguments.of(E2), Arguments.of(F2), Arguments.of(G2), Arguments.of(H2), + + Arguments.of(A7), Arguments.of(B7), Arguments.of(C7), Arguments.of(D7), + Arguments.of(E7), Arguments.of(F7), Arguments.of(G7), Arguments.of(H7) + ); + } + + @MethodSource + @ParameterizedTest + void 체스_보드를_생성하면_일선에_기물들이_존재한다(Position position, Piece piece) { + Board board = new Board(); + + assertThat(board.findByPosition(position)).isEqualTo(piece); + } + + private static Stream 체스_보드를_생성하면_일선에_기물들이_존재한다() { + return Stream.of( + Arguments.of(A1, new Rook(Team.A, A1)), Arguments.of(H1, new Rook(Team.A, H1)), + Arguments.of(A8, new Rook(Team.B, A8)), Arguments.of(H8, new Rook(Team.B, H8)), + Arguments.of(B1, new Knight(Team.A, B1)), Arguments.of(G1, new Knight(Team.A, G1)), + Arguments.of(B8, new Knight(Team.B, B8)), Arguments.of(G8, new Knight(Team.B, G8)), + Arguments.of(C1, new Bishop(Team.A, C1)), Arguments.of(F1, new Bishop(Team.A, F1)), + Arguments.of(C8, new Bishop(Team.B, C8)), Arguments.of(F8, new Bishop(Team.B, F8)), + Arguments.of(D1, new Queen(Team.A, D1)), Arguments.of(D8, new Queen(Team.B, D8)), + Arguments.of(E1, new King(Team.A, E1)), Arguments.of(E8, new King(Team.B, E8)) + ); + } + +} diff --git a/src/test/java/chess/piece/BishopTest.java b/src/test/java/chess/piece/BishopTest.java new file mode 100644 index 00000000000..f40ba8b4672 --- /dev/null +++ b/src/test/java/chess/piece/BishopTest.java @@ -0,0 +1,73 @@ +package chess.piece; + +import static chess.Fixtures.C3; +import static chess.Fixtures.C5; +import static chess.Fixtures.D4; +import static chess.Fixtures.E3; +import static chess.Fixtures.E5; +import static chess.Movement.DOWN_DOWN_LEFT; +import static chess.Movement.DOWN_DOWN_RIGHT; +import static chess.Movement.LEFT_DOWN; +import static chess.Movement.LEFT_LEFT_DOWN; +import static chess.Movement.LEFT_LEFT_UP; +import static chess.Movement.LEFT_UP; +import static chess.Movement.RIGHT_DOWN; +import static chess.Movement.RIGHT_RIGHT_DOWN; +import static chess.Movement.RIGHT_RIGHT_UP; +import static chess.Movement.RIGHT_UP; +import static chess.Movement.UP_UP_LEFT; +import static chess.Movement.UP_UP_RIGHT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import chess.Movement; +import chess.Position; + +class BishopTest { + + @MethodSource + @ParameterizedTest + void 비숍은_원하는_만큼_대각선으로_이동한다(Movement movement, Position position) { + Bishop bishop = new Bishop(Team.A, D4); + + assertThat(bishop.move(movement)).isEqualTo(new Bishop(Team.A, position)); + } + + private static Stream 비숍은_원하는_만큼_대각선으로_이동한다() { + return Stream.of( + Arguments.of(LEFT_UP, C5), + Arguments.of(RIGHT_UP, E5), + Arguments.of(LEFT_DOWN, C3), + Arguments.of(RIGHT_DOWN, E3) + ); + } + + @MethodSource + @ParameterizedTest + void 바숍이_이동할_수_없다(Movement movement) { + Bishop bishop = new Bishop(Team.A, D4); + + assertThatThrownBy(() -> bishop.move(movement)) + .isInstanceOf(IllegalArgumentException.class); + } + + private static Stream 바숍이_이동할_수_없다() { + return Stream.of( + Arguments.of(LEFT_LEFT_UP), + Arguments.of(LEFT_LEFT_DOWN), + Arguments.of(RIGHT_RIGHT_DOWN), + Arguments.of(RIGHT_RIGHT_UP), + Arguments.of(UP_UP_LEFT), + Arguments.of(UP_UP_RIGHT), + Arguments.of(DOWN_DOWN_LEFT), + Arguments.of(DOWN_DOWN_RIGHT) + ); + } + +} diff --git a/src/test/java/chess/piece/KingTest.java b/src/test/java/chess/piece/KingTest.java new file mode 100644 index 00000000000..1acaf3dd5bc --- /dev/null +++ b/src/test/java/chess/piece/KingTest.java @@ -0,0 +1,52 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import chess.Column; +import chess.Movement; +import chess.Position; +import chess.Row; + +class KingTest { + + @MethodSource + @ParameterizedTest + void 킹은_직선을_한칸_움직일_수_있다(Movement movement, Position target) { + King king = new King(Team.A, new Position(Row.TWO, Column.D)); + + assertThat(king.move(movement)).isEqualTo(new King(Team.A, target)); + } + + private static Stream 킹은_직선을_한칸_움직일_수_있다() { + return Stream.of( + Arguments.of(Movement.UP, new Position(Row.THREE, Column.D)), + Arguments.of(Movement.DOWN, new Position(Row.ONE, Column.D)), + Arguments.of(Movement.LEFT, new Position(Row.TWO, Column.C)), + Arguments.of(Movement.RIGHT, new Position(Row.TWO, Column.E)) + ); + } + + @MethodSource + @ParameterizedTest + void 킹은_대각선을_한칸_움직일_수_있다(Movement movement, Position target) { + King king = new King(Team.A, new Position(Row.TWO, Column.D)); + + assertThat(king.move(movement)).isEqualTo(new King(Team.A, target)); + } + + private static Stream 킹은_대각선을_한칸_움직일_수_있다() { + return Stream.of( + Arguments.of(Movement.LEFT_UP, new Position(Row.THREE, Column.C)), + Arguments.of(Movement.RIGHT_UP, new Position(Row.THREE, Column.E)), + Arguments.of(Movement.LEFT_DOWN, new Position(Row.ONE, Column.C)), + Arguments.of(Movement.RIGHT_DOWN, new Position(Row.ONE, Column.E)) + ); + } + +} diff --git a/src/test/java/chess/piece/KnightTest.java b/src/test/java/chess/piece/KnightTest.java new file mode 100644 index 00000000000..acb08d98897 --- /dev/null +++ b/src/test/java/chess/piece/KnightTest.java @@ -0,0 +1,73 @@ +package chess.piece; + +import static chess.Movement.DOWN_DOWN_LEFT; +import static chess.Movement.DOWN_DOWN_RIGHT; +import static chess.Movement.LEFT_LEFT_DOWN; +import static chess.Movement.LEFT_LEFT_UP; +import static chess.Movement.RIGHT_RIGHT_DOWN; +import static chess.Movement.RIGHT_RIGHT_UP; +import static chess.Movement.UP_UP; +import static chess.Movement.UP_UP_LEFT; +import static chess.Movement.UP_UP_RIGHT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import chess.Column; +import chess.Fixtures; +import chess.Movement; +import chess.Position; +import chess.Row; + +class KnightTest { + + @MethodSource + @ParameterizedTest + void 나이트는_한_방향_두_칸_그와_90도를_이루는_방향_한_칸을_움직일_수_있다(Movement movement, Position position) { + Knight knight = new Knight(Team.A, new Position(Row.THREE, Column.D)); + + assertThat(knight.move(movement)).isEqualTo(new Knight(Team.A, position)); + } + + private static Stream 나이트는_한_방향_두_칸_그와_90도를_이루는_방향_한_칸을_움직일_수_있다() { + return Stream.of( + Arguments.of(LEFT_LEFT_UP, new Position(Row.FOUR, Column.B)), + Arguments.of(LEFT_LEFT_DOWN, new Position(Row.TWO, Column.B)), + Arguments.of(RIGHT_RIGHT_UP, new Position(Row.FOUR, Column.F)), + Arguments.of(RIGHT_RIGHT_DOWN, new Position(Row.TWO, Column.F)), + Arguments.of(UP_UP_LEFT, new Position(Row.FIVE, Column.C)), + Arguments.of(UP_UP_RIGHT, new Position(Row.FIVE, Column.E)), + Arguments.of(DOWN_DOWN_LEFT, new Position(Row.ONE, Column.C)), + Arguments.of(DOWN_DOWN_RIGHT, new Position(Row.ONE, Column.E)) + ); + } + + @MethodSource + @ParameterizedTest + void 나이트가_움직일_수_없다(Position position, Movement movement) { + Knight knight = new Knight(Team.A, position); + + assertThatThrownBy(() -> knight.move(movement)) + .isInstanceOf(IllegalArgumentException.class); + } + + private static Stream 나이트가_움직일_수_없다() { + return Stream.of( + Arguments.of(Fixtures.F8, LEFT_LEFT_UP), + Arguments.of(Fixtures.F1, LEFT_LEFT_DOWN), + Arguments.of(Fixtures.G8, RIGHT_RIGHT_UP), + Arguments.of(Fixtures.G8, RIGHT_RIGHT_DOWN), + Arguments.of(Fixtures.A6, UP_UP_LEFT), + Arguments.of(Fixtures.H6, UP_UP_RIGHT), + Arguments.of(Fixtures.A3, DOWN_DOWN_LEFT), + Arguments.of(Fixtures.A2, DOWN_DOWN_RIGHT), + Arguments.of(Fixtures.A2, UP_UP) + ); + } + +} diff --git a/src/test/java/chess/piece/PawnTest.java b/src/test/java/chess/piece/PawnTest.java new file mode 100644 index 00000000000..29e24a78ed2 --- /dev/null +++ b/src/test/java/chess/piece/PawnTest.java @@ -0,0 +1,52 @@ +package chess.piece; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; + +import chess.Fixtures; +import chess.Movement; + +class PawnTest { + + @Test + void 폰은_앞으로_한칸_움직인다() { + Pawn pawn = new Pawn(Team.A, Fixtures.A2); + + assertThat(pawn.move(Movement.UP)).isEqualTo(new Pawn(Team.A, Fixtures.A3)); + } + + @Test + void 처음_움직이는_폰은_앞으로_두칸_움직일_수_있다() { + Pawn pawn = new Pawn(Team.A, Fixtures.A2); + + assertThat(pawn.move(Movement.UP_UP)).isEqualTo(new Pawn(Team.A, Fixtures.A4)); + } + + @Test + void 이미_움직인_폰은_앞으로_두칸_갈_수_없다() { + Pawn pawn = new Pawn(Team.A, Fixtures.A2); + Pawn movedPawn = pawn.move(Movement.UP_UP); + + assertThatThrownBy(() -> movedPawn.move(Movement.UP_UP)) + .isInstanceOf(IllegalArgumentException.class); + } + + @EnumSource( + value = Movement.class, + names = {"UP", "UP_UP"}, + mode = Mode.EXCLUDE + ) + @ParameterizedTest + void 폰이_움직일_수_없다(Movement movement) { + Pawn pawn = new Pawn(Team.A, Fixtures.A2); + + assertThatThrownBy(() -> pawn.move(movement)) + .isInstanceOf(IllegalArgumentException.class); + } + +} diff --git a/src/test/java/chess/piece/QueenTest.java b/src/test/java/chess/piece/QueenTest.java new file mode 100644 index 00000000000..29223e36fba --- /dev/null +++ b/src/test/java/chess/piece/QueenTest.java @@ -0,0 +1,82 @@ +package chess.piece; + +import static chess.Movement.DOWN; +import static chess.Movement.LEFT; +import static chess.Movement.LEFT_DOWN; +import static chess.Movement.LEFT_LEFT_DOWN; +import static chess.Movement.LEFT_UP; +import static chess.Movement.RIGHT; +import static chess.Movement.RIGHT_DOWN; +import static chess.Movement.RIGHT_UP; +import static chess.Movement.UP; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import chess.Column; +import chess.Movement; +import chess.Position; +import chess.Row; + +class QueenTest { + + @MethodSource + @ParameterizedTest + void 퀸은_일직선으로_원하는_만큼_이동한다(Movement movement, Position position) { + Queen queen = new Queen(Team.A, new Position(Row.THREE, Column.D)); + + assertThat(queen.move(movement)).isEqualTo(new Queen(Team.A, position)); + } + + private static Stream 퀸은_일직선으로_원하는_만큼_이동한다() { + return Stream.of( + Arguments.of(LEFT, new Position(Row.THREE, Column.C)), + Arguments.of(RIGHT, new Position(Row.THREE, Column.E)), + Arguments.of(UP, new Position(Row.FOUR, Column.D)), + Arguments.of(DOWN, new Position(Row.TWO, Column.D)) + ); + } + + @MethodSource + @ParameterizedTest + void 퀸은_대각선으로_원하는_만큼_이동한다(Movement movement, Position position) { + Queen queen = new Queen(Team.A, new Position(Row.THREE, Column.D)); + + assertThat(queen.move(movement)).isEqualTo(new Queen(Team.A, position)); + } + + private static Stream 퀸은_대각선으로_원하는_만큼_이동한다() { + return Stream.of( + Arguments.of(LEFT_UP, new Position(Row.FOUR, Column.C)), + Arguments.of(RIGHT_UP, new Position(Row.FOUR, Column.E)), + Arguments.of(LEFT_DOWN, new Position(Row.TWO, Column.C)), + Arguments.of(RIGHT_DOWN, new Position(Row.TWO, Column.E)) + ); + } + + @MethodSource + @ParameterizedTest + void 퀸이_움직일_수_없다(Movement movement) { + Queen queen = new Queen(Team.A, new Position(Row.ONE, Column.A)); + + assertThatThrownBy(() -> queen.move(movement)) + .isInstanceOf(IllegalArgumentException.class); + } + + private static Stream 퀸이_움직일_수_없다() { + return Stream.of( + Arguments.of(LEFT_LEFT_DOWN), + Arguments.of(LEFT), + Arguments.of(DOWN), + Arguments.of(LEFT_DOWN), + Arguments.of(LEFT_UP), + Arguments.of(RIGHT_DOWN) + ); + } + +} diff --git a/src/test/java/chess/piece/RookTest.java b/src/test/java/chess/piece/RookTest.java new file mode 100644 index 00000000000..e4fb9d8e042 --- /dev/null +++ b/src/test/java/chess/piece/RookTest.java @@ -0,0 +1,62 @@ +package chess.piece; + +import static chess.Movement.DOWN; +import static chess.Movement.LEFT; +import static chess.Movement.LEFT_DOWN; +import static chess.Movement.LEFT_UP; +import static chess.Movement.RIGHT; +import static chess.Movement.RIGHT_DOWN; +import static chess.Movement.RIGHT_UP; +import static chess.Movement.UP; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import chess.Column; +import chess.Movement; +import chess.Position; +import chess.Row; + +class RookTest { + + @MethodSource + @ParameterizedTest + void 룩은_원하는_만큼_직선으로_이동할_수_있다(Movement movement, Position position) { + Rook rook = new Rook(Team.A, new Position(Row.THREE, Column.D)); + + assertThat(rook.move(movement)).isEqualTo(new Rook(Team.A, position)); + } + + private static Stream 룩은_원하는_만큼_직선으로_이동할_수_있다() { + return Stream.of( + Arguments.of(UP, new Position(Row.FOUR, Column.D)), + Arguments.of(LEFT, new Position(Row.THREE, Column.C)), + Arguments.of(RIGHT, new Position(Row.THREE, Column.E)), + Arguments.of(DOWN, new Position(Row.TWO, Column.D)) + ); + } + + @MethodSource + @ParameterizedTest + void 룩이_이동할_수_없다(Movement movement) { + Rook rook = new Rook(Team.A, new Position(Row.ONE, Column.A)); + + assertThatThrownBy(() -> rook.move(movement)) + .isInstanceOf(IllegalArgumentException.class); + } + + private static Stream 룩이_이동할_수_없다() { + return Stream.of( + Arguments.of(LEFT_UP), + Arguments.of(RIGHT_UP), + Arguments.of(LEFT_DOWN), + Arguments.of(RIGHT_DOWN) + ); + } + +}