diff --git a/build.gradle b/build.gradle index 3697236c6fb..ce846f70cc6 100644 --- a/build.gradle +++ b/build.gradle @@ -9,15 +9,15 @@ repositories { } dependencies { - testImplementation platform('org.junit:junit-bom:5.9.1') - testImplementation platform('org.assertj:assertj-bom:3.25.1') + testImplementation platform('org.junit:junit-bom:5.11.4') + testImplementation platform('org.assertj:assertj-bom:3.27.3') testImplementation('org.junit.jupiter:junit-jupiter') testImplementation('org.assertj:assertj-core') } java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b..e6441136f3d 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 80187ac3043..b82aa23a4f0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew.bat b/gradlew.bat index 6689b85beec..7101f8e4676 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/src/main/java/chess/Application.java b/src/main/java/chess/Application.java new file mode 100644 index 00000000000..ed75c04d0f2 --- /dev/null +++ b/src/main/java/chess/Application.java @@ -0,0 +1,8 @@ +package chess; + +public class Application { + public static void main(String[] args) { + Game game = new Game(); + game.start(); + } +} diff --git a/src/main/java/chess/Board.java b/src/main/java/chess/Board.java new file mode 100644 index 00000000000..9833bfffa51 --- /dev/null +++ b/src/main/java/chess/Board.java @@ -0,0 +1,83 @@ +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.HashMap; +import java.util.Map; + +public class Board { + private final Map positions; + + public Board() { + positions = new HashMap<>(); + positions.put(new Position(Column.D, Row.ONE), new King(Color.BLACK, new Position(Column.D, Row.ONE))); + positions.put(new Position(Column.E, Row.ONE), new Queen(Color.BLACK, new Position(Column.E, Row.ONE))); + positions.put(new Position(Column.C, Row.ONE), new Bishop(Color.BLACK, new Position(Column.C, Row.ONE))); + positions.put(new Position(Column.F, Row.ONE), new Bishop(Color.BLACK, new Position(Column.F, Row.ONE))); + positions.put(new Position(Column.B, Row.ONE), new Knight(Color.BLACK, new Position(Column.B, Row.ONE))); + positions.put(new Position(Column.G, Row.ONE), new Knight(Color.BLACK, new Position(Column.G, Row.ONE))); + positions.put(new Position(Column.A, Row.ONE), new Rook(Color.BLACK, new Position(Column.A, Row.ONE))); + positions.put(new Position(Column.H, Row.ONE), new Rook(Color.BLACK, new Position(Column.H, Row.ONE))); + positions.put(new Position(Column.A, Row.TWO), new Pawn(Color.BLACK, new Position(Column.A, Row.TWO))); + positions.put(new Position(Column.B, Row.TWO), new Pawn(Color.BLACK, new Position(Column.B, Row.TWO))); + positions.put(new Position(Column.C, Row.TWO), new Pawn(Color.BLACK, new Position(Column.C, Row.TWO))); + positions.put(new Position(Column.D, Row.TWO), new Pawn(Color.BLACK, new Position(Column.D, Row.TWO))); + positions.put(new Position(Column.E, Row.TWO), new Pawn(Color.BLACK, new Position(Column.E, Row.TWO))); + positions.put(new Position(Column.F, Row.TWO), new Pawn(Color.BLACK, new Position(Column.F, Row.TWO))); + positions.put(new Position(Column.G, Row.TWO), new Pawn(Color.BLACK, new Position(Column.G, Row.TWO))); + positions.put(new Position(Column.H, Row.TWO), new Pawn(Color.BLACK, new Position(Column.H, Row.TWO))); + + positions.put(new Position(Column.D, Row.EIGHT), new King(Color.WHITE, new Position(Column.D, Row.EIGHT))); + positions.put(new Position(Column.E, Row.EIGHT), new Queen(Color.WHITE, new Position(Column.E, Row.EIGHT))); + positions.put(new Position(Column.C, Row.EIGHT), new Bishop(Color.WHITE, new Position(Column.C, Row.EIGHT))); + positions.put(new Position(Column.F, Row.EIGHT), new Bishop(Color.WHITE, new Position(Column.F, Row.EIGHT))); + positions.put(new Position(Column.B, Row.EIGHT), new Knight(Color.WHITE, new Position(Column.B, Row.EIGHT))); + positions.put(new Position(Column.G, Row.EIGHT), new Knight(Color.WHITE, new Position(Column.G, Row.EIGHT))); + positions.put(new Position(Column.A, Row.EIGHT), new Rook(Color.WHITE, new Position(Column.A, Row.EIGHT))); + positions.put(new Position(Column.H, Row.EIGHT), new Rook(Color.WHITE, new Position(Column.H, Row.EIGHT))); + positions.put(new Position(Column.A, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.A, Row.SEVEN))); + positions.put(new Position(Column.B, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.B, Row.SEVEN))); + positions.put(new Position(Column.C, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.C, Row.SEVEN))); + positions.put(new Position(Column.D, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.D, Row.SEVEN))); + positions.put(new Position(Column.E, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.E, Row.SEVEN))); + positions.put(new Position(Column.F, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.F, Row.SEVEN))); + positions.put(new Position(Column.G, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.G, Row.SEVEN))); + positions.put(new Position(Column.H, Row.SEVEN), new Pawn(Color.WHITE, new Position(Column.H, Row.SEVEN))); + } + + public void movePiece(Position start, Position end) { + validateHavingPieceAt(start); + Piece piece = positions.get(start); + if (positions.containsKey(end) && piece.getColor() == positions.get(end).getColor()) { + throw new IllegalArgumentException("같은 팀 말이 있는 곳으로 갈 수 없습니다."); + } + if (piece.isMovableTo(end, positions)) { + if (positions.containsKey(end)) { + System.out.println("상대팀 말을 잡았습니다."); + } + positions.remove(start); + positions.put(end, piece.moveTo(end)); + } else { + System.out.println("움직일 수 없는 위치입니다."); + } + } + + public boolean hasPieceAt(Position position) { + return positions.containsKey(position); + } + + public Piece getPiece(Position position) { + return positions.get(position); + } + + private void validateHavingPieceAt(Position position) { + if (!hasPieceAt(position)) { + throw new IllegalArgumentException("해당 위치에 움직일 말이 존재하지 않습니다."); + } + } +} diff --git a/src/main/java/chess/Color.java b/src/main/java/chess/Color.java new file mode 100644 index 00000000000..55cd020b681 --- /dev/null +++ b/src/main/java/chess/Color.java @@ -0,0 +1,28 @@ +package chess; + +public enum Color { + + BLACK, + WHITE, + EMPTY; + + public boolean isWhite() { + return this == WHITE; + } + + public boolean isBlack() { + return this == BLACK; + } + + public boolean isEmpty() { + return this == EMPTY; + } + + public Color opposite() { + return switch (this) { + case BLACK -> WHITE; + case WHITE -> BLACK; + default -> EMPTY; + }; + } +} diff --git a/src/main/java/chess/Column.java b/src/main/java/chess/Column.java new file mode 100644 index 00000000000..b64b4dc77a3 --- /dev/null +++ b/src/main/java/chess/Column.java @@ -0,0 +1,53 @@ +package chess; + +public enum Column { + + A, + B, + C, + D, + E, + F, + G, + H; + + public boolean isFarLeft() { + return ordinal() == 0; + } + + public boolean isFarRight() { + return ordinal() + 1 == values().length; + } + + public boolean canMoveLeft(final int step) { + return ordinal() - step >= 0; + } + + public Column moveLeft() { + return moveLeft(1); + } + + public Column moveLeft(final int step) { + if (canMoveLeft(step)) { + return values()[ordinal() - step]; + } + + throw new IllegalStateException("움직일 수 없는 위치입니다."); + } + + public boolean canMoveRight(final int step) { + return ordinal() + step < values().length; + } + + public Column moveRight() { + return moveRight(1); + } + + public Column moveRight(final int step) { + if (canMoveRight(step)) { + return values()[ordinal() + step]; + } + + throw new IllegalStateException("움직일 수 없는 위치입니다."); + } +} diff --git a/src/main/java/chess/Game.java b/src/main/java/chess/Game.java new file mode 100644 index 00000000000..3c9b6f07e21 --- /dev/null +++ b/src/main/java/chess/Game.java @@ -0,0 +1,16 @@ +package chess; + +import chess.view.InputView; +import chess.view.OutputView; + +public class Game { + public void start() { + Board board = new Board(); + while (true) { + OutputView.printBoard(board); + Position start = InputView.readStartPosition(); + Position end = InputView.readEndPosition(); + board.movePiece(start, end); + } + } +} diff --git a/src/main/java/chess/Movement.java b/src/main/java/chess/Movement.java new file mode 100644 index 00000000000..e57c6e91bb9 --- /dev/null +++ b/src/main/java/chess/Movement.java @@ -0,0 +1,48 @@ +package chess; + +public enum Movement { + UP(0, 1), + UP_UP(UP.x * 2, UP.y * 2), + DOWN(0, -1), + DOWN_DOWN(DOWN.x * 2, DOWN.y * 2), + LEFT(-1, 0), + RIGHT(1, 0), + LEFT_UP(LEFT.x, UP.y), + RIGHT_UP(RIGHT.x, UP.y), + LEFT_DOWN(LEFT.x, DOWN.y), + RIGHT_DOWN(RIGHT.x, DOWN.y), + UP_UP_LEFT(LEFT_DOWN.x, UP_UP.y), + UP_UP_RIGHT(RIGHT_DOWN.x, UP_UP.y), + LEFT_LEFT_UP(LEFT.x * 2, UP.y), + LEFT_LEFT_DOWN(LEFT.x * 2, DOWN.y), + RIGHT_RIGHT_UP(RIGHT.x * 2, UP.y), + RIGHT_RIGHT_DOWN(RIGHT.x * 2, DOWN.y), + DOWN_DOWN_LEFT(LEFT_DOWN.x, DOWN_DOWN.y), + DOWN_DOWN_RIGHT(RIGHT_DOWN.x, DOWN_DOWN.y), + ; + + private final int x; + + private final int y; + + Movement(final int x, final int y) { + this.x = x; + this.y = y; + } + + public int x() { + return x; + } + + public int y() { + return y; + } + + public boolean isVertical() { + 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/Position.java b/src/main/java/chess/Position.java new file mode 100644 index 00000000000..3ebeb0ea185 --- /dev/null +++ b/src/main/java/chess/Position.java @@ -0,0 +1,170 @@ +package chess; + +public record Position( + Column column, + Row row +) { + public Position(final Row row, final Column column) { + this(column, row); + } + + public boolean canMoveUp() { + return row.canMoveUp(1); + } + + public boolean canMoveUp(final int step) { + return row.canMoveUp(step); + } + + public Position moveUp() { + return moveUp(1); + } + + public Position moveUp(final int step) { + return new Position(row.moveUp(step), column); + } + + public boolean canMoveDown() { + return canMoveDown(1); + } + + public boolean canMoveDown(final int step) { + return row.canMoveDown(step); + } + + public Position moveDown() { + return moveDown(1); + } + + public Position moveDown(final int step) { + return new Position(row.moveDown(step), column); + } + + public boolean canMoveLeft() { + return canMoveLeft(1); + } + + public boolean canMoveLeft(final int step) { + return column.canMoveLeft(step); + } + + public Position moveLeft() { + return moveLeft(1); + } + + public Position moveLeft(final int step) { + return new Position(row, column.moveLeft(step)); + } + + public boolean canMoveRight() { + return canMoveRight(1); + } + + public boolean canMoveRight(final int step) { + return column.canMoveRight(step); + } + + public Position moveRight() { + return moveRight(1); + } + + public Position moveRight(final int step) { + return new Position(row, column.moveRight(step)); + } + + public boolean canMoveLeftUp() { + return canMoveLeft() && canMoveUp(); + } + + public Position moveLeftUp() { + return moveLeft().moveUp(); + } + + public boolean canMoveLeftDown() { + return canMoveLeft() && canMoveDown(); + } + + public Position moveLeftDown() { + return moveLeft().moveDown(); + } + + public boolean canMoveRightUp() { + return canMoveUp() && canMoveRight(); + } + + public Position moveRightUp() { + return moveRight().moveUp(); + } + + public boolean canMoveRightDown() { + return canMoveRight() && canMoveDown(); + } + + public Position moveRightDown() { + return moveRight().moveDown(); + } + + public boolean isTop() { + return row.isTop(); + } + + public boolean isBottom() { + return row.isBottom(); + } + + public boolean isFarLeft() { + return column.isFarLeft(); + } + + public boolean isFarRight() { + return column.isFarRight(); + } + + public boolean canMove(final Movement movement) { + return canMoveVertical(movement.y()) && canMoveHorizontal(movement.x()); + } + + public boolean canMoveVertical(final int step) { + if (step > 0) { + return canMoveUp(step); + } + if (step < 0) { + return canMoveDown(-step); + } + return true; + } + + public boolean canMoveHorizontal(final int step) { + if (step > 0) { + return canMoveRight(step); + } + if (step < 0) { + return canMoveLeft(-step); + } + return true; + } + + public Position move(final Movement movement) { + return moveVertical(movement.y()).moveHorizontal(movement.x()); + } + + public Position moveVertical(final int step) { + if (step > 0) { + return moveUp(step); + } + if (step < 0) { + return moveDown(-step); + } + return this; + } + + public Position moveHorizontal(final int step) { + if (step > 0) { + return moveRight(step); + } + if (step < 0) { + return moveLeft(-step); + } + return this; + } +} diff --git a/src/main/java/chess/Row.java b/src/main/java/chess/Row.java new file mode 100644 index 00000000000..126ed048daa --- /dev/null +++ b/src/main/java/chess/Row.java @@ -0,0 +1,53 @@ +package chess; + +public enum Row { + + EIGHT, + SEVEN, + SIX, + FIVE, + FOUR, + THREE, + TWO, + ONE; + + public boolean isTop() { + return ordinal() == 0; + } + + public boolean isBottom() { + return ordinal() + 1 == values().length; + } + + public boolean canMoveUp(final int step) { + return ordinal() - step >= 0; + } + + public Row moveUp() { + return moveUp(1); + } + + public Row moveUp(final int step) { + if (canMoveUp(step)) { + return values()[ordinal() - step]; + } + + throw new IllegalStateException("움직일 수 없는 위치입니다."); + } + + public boolean canMoveDown(final int step) { + return ordinal() + step < values().length; + } + + public Row moveDown() { + return moveDown(1); + } + + public Row moveDown(final int step) { + if (canMoveDown(step)) { + return values()[ordinal() + step]; + } + + throw new IllegalStateException("움직일 수 없는 위치입니다."); + } +} diff --git a/src/main/java/chess/piece/AbstractPiece.java b/src/main/java/chess/piece/AbstractPiece.java new file mode 100644 index 00000000000..b95aa88b4e3 --- /dev/null +++ b/src/main/java/chess/piece/AbstractPiece.java @@ -0,0 +1,28 @@ +package chess.piece; + +import chess.Color; +import chess.Position; + +public abstract class AbstractPiece implements Piece { + private final String name; + private final Color color; + private final Position position; + + public AbstractPiece(final String name, final Color color, final Position position) { + this.name = name; + this.color = color; + this.position = position; + } + + public String getName() { + return name; + } + + public Color getColor() { + return color; + } + + public Position getPosition() { + return position; + } +} diff --git a/src/main/java/chess/piece/Bishop.java b/src/main/java/chess/piece/Bishop.java new file mode 100644 index 00000000000..1fb411deb1f --- /dev/null +++ b/src/main/java/chess/piece/Bishop.java @@ -0,0 +1,87 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public class Bishop extends AbstractPiece { + + public Bishop(Color color, Position position) { + super("B", color, position); + } + + @Override + public Bishop moveTo(Position destination) { + return new Bishop(getColor(), destination); + } + + @Override + public boolean isMovableTo(Position destination, final Map positions) { + if (canMoveLeftUp(getPosition(), destination, positions)) { + return true; + } + if (canMoveLeftDown(getPosition(), destination, positions)) { + return true; + } + if (canMoveRightUp(getPosition(), destination, positions)) { + return true; + } + return canMoveRightDown(getPosition(), destination, positions); + } + + private boolean canMoveLeftUp(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveLeftUp()) { + target = target.moveLeftUp(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveLeftDown(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveLeftDown()) { + target = target.moveLeftDown(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveRightUp(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveRightUp()) { + target = target.moveRightUp(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveRightDown(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveRightDown()) { + target = target.moveRightDown(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } +} diff --git a/src/main/java/chess/piece/King.java b/src/main/java/chess/piece/King.java new file mode 100644 index 00000000000..5a6c5dc62f8 --- /dev/null +++ b/src/main/java/chess/piece/King.java @@ -0,0 +1,58 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public class King extends AbstractPiece { + + public King(Color color, Position position) { + super("K", color, position); + } + + public King moveTo(Position destination) { + return new King(getColor(), destination); + } + + public boolean isMovableTo(Position destination, final Map positions) { + if (canMoveUp(destination) || canMoveDown(destination) || canMoveLeft(destination) || canMoveRight(destination)) { + return true; + } + if (canMoveLeftUp(destination) || canMoveLeftDown(destination) || canMoveRightUp(destination) || canMoveRightDown(destination)) { + return true; + } + return false; + } + + private boolean canMoveUp(Position destination) { + return getPosition().canMoveUp() && getPosition().moveUp().equals(destination); + } + + private boolean canMoveDown(Position destination) { + return getPosition().canMoveDown() && getPosition().moveDown().equals(destination); + } + + private boolean canMoveLeft(Position destination) { + return getPosition().canMoveLeft() && getPosition().moveLeft().equals(destination); + } + + private boolean canMoveRight(Position destination) { + return getPosition().canMoveRight() && getPosition().moveRight().equals(destination); + } + + private boolean canMoveLeftUp(Position destination) { + return getPosition().canMoveLeftUp() && getPosition().moveLeftUp().equals(destination); + } + + private boolean canMoveLeftDown(Position destination) { + return getPosition().canMoveLeftDown() && getPosition().moveLeftDown().equals(destination); + } + + private boolean canMoveRightUp(Position destination) { + return getPosition().canMoveRightUp() && getPosition().moveRightUp().equals(destination); + } + + private boolean canMoveRightDown(Position destination) { + return getPosition().canMoveRightDown() && getPosition().moveRightDown().equals(destination); + } +} diff --git a/src/main/java/chess/piece/Knight.java b/src/main/java/chess/piece/Knight.java new file mode 100644 index 00000000000..2b2f811ba7a --- /dev/null +++ b/src/main/java/chess/piece/Knight.java @@ -0,0 +1,107 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public class Knight extends AbstractPiece { + + public Knight(Color color, Position position) { + super("N", color, position); + } + + @Override + public Knight moveTo(Position destination) { + return new Knight(getColor(), destination); + } + + @Override + public boolean isMovableTo(Position destination, final Map positions) { + if (canMoveUpLeftUp() && moveUpLeftUp().equals(destination)) { + return true; + } + if (canMoveUpRightUp() && moveUpRightUp().equals(destination)) { + return true; + } + if (canMoveDownLeftDown() && moveDownLeftDown().equals(destination)) { + return true; + } + if (canMoveDownRightDown() && moveDownRightDown().equals(destination)) { + return true; + } + if (canMoveLeftLeftUp() && moveLeftLeftUp().equals(destination)) { + return true; + } + if (canMoveLeftLeftDown() && moveLeftLeftDown().equals(destination)) { + return true; + } + if (canMoveRightRightUp() && moveRightRightUp().equals(destination)) { + return true; + } + return canMoveRightRightDown() && moveRightRightDown().equals(destination); + } + + private boolean canMoveUpLeftUp() { + return getPosition().canMoveUp() && getPosition().moveUp().canMoveLeftUp(); + } + + private Position moveUpLeftUp() { + return getPosition().moveUp().moveLeftUp(); + } + + private boolean canMoveUpRightUp() { + return getPosition().canMoveUp() && getPosition().moveUp().canMoveRightUp(); + } + + private Position moveUpRightUp() { + return getPosition().moveUp().moveRightUp(); + } + + private boolean canMoveDownLeftDown() { + return getPosition().canMoveDown() && getPosition().moveDown().canMoveLeftDown(); + } + + private Position moveDownLeftDown() { + return getPosition().moveDown().moveLeftDown(); + } + + private boolean canMoveDownRightDown() { + return getPosition().canMoveDown() && getPosition().moveDown().canMoveRightDown(); + } + + private Position moveDownRightDown() { + return getPosition().moveDown().moveRightDown(); + } + + private boolean canMoveLeftLeftUp() { + return getPosition().canMoveLeft() && getPosition().moveLeft().canMoveLeftUp(); + } + + private Position moveLeftLeftUp() { + return getPosition().moveLeft().moveLeftUp(); + } + + private boolean canMoveLeftLeftDown() { + return getPosition().canMoveLeft() && getPosition().moveLeft().canMoveLeftDown(); + } + + private Position moveLeftLeftDown() { + return getPosition().moveLeft().moveLeftDown(); + } + + private boolean canMoveRightRightUp() { + return getPosition().canMoveRight() && getPosition().moveRight().canMoveRightUp(); + } + + private Position moveRightRightUp() { + return getPosition().moveRight().moveRightUp(); + } + + private boolean canMoveRightRightDown() { + return getPosition().canMoveRight() && getPosition().moveRightUp().canMoveRightDown(); + } + + private Position moveRightRightDown() { + return getPosition().moveRight().moveRightDown(); + } +} diff --git a/src/main/java/chess/piece/Pawn.java b/src/main/java/chess/piece/Pawn.java new file mode 100644 index 00000000000..b2eb4a60a1d --- /dev/null +++ b/src/main/java/chess/piece/Pawn.java @@ -0,0 +1,71 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public class Pawn extends AbstractPiece { + + public Pawn(Color color, Position position) { + super("P", color, position); + } + + @Override + public Piece moveTo(final Position position) { + return new Pawn(getColor(), position); + } + + @Override + public boolean isMovableTo(final Position destination, final Map positions) { + if (getColor() == Color.BLACK) { + if (getPosition().moveUp().equals(destination)) { + return true; + } + if (getPosition().moveDown().isBottom() && getPosition().moveUp().moveUp().equals(destination)) { + return true; + } + if (positions.containsKey(destination) && canMoveLeftUp() && getPosition().moveLeftUp() + .equals(destination)) { + return true; + } + if (positions.containsKey(destination) && canMoveRightUp() && getPosition().moveRightUp() + .equals(destination)) { + return true; + } + return false; + + } else { + if (getPosition().moveDown().equals(destination)) { + return true; + } + if (getPosition().moveUp().isTop() && getPosition().moveDown().moveDown().equals(destination)) { + return true; + } + if (positions.containsKey(destination) && canMoveLeftDown() && getPosition().moveLeftDown() + .equals(destination)) { + return true; + } + if (positions.containsKey(destination) && canMoveRightDown() && getPosition().moveRightDown() + .equals(destination)) { + return true; + } + return false; + } + } + + private boolean canMoveLeftDown() { + return getPosition().canMoveLeftDown(); + } + + private boolean canMoveRightDown() { + return getPosition().canMoveRightDown(); + } + + private boolean canMoveLeftUp() { + return getPosition().canMoveLeftUp(); + } + + private boolean canMoveRightUp() { + return getPosition().canMoveRightUp(); + } +} diff --git a/src/main/java/chess/piece/Piece.java b/src/main/java/chess/piece/Piece.java new file mode 100644 index 00000000000..49bacb238b2 --- /dev/null +++ b/src/main/java/chess/piece/Piece.java @@ -0,0 +1,13 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public interface Piece { + boolean isMovableTo(Position position, final Map positions); + Piece moveTo(Position position); + String getName(); + Color getColor(); + Position getPosition(); +} diff --git a/src/main/java/chess/piece/Queen.java b/src/main/java/chess/piece/Queen.java new file mode 100644 index 00000000000..b712988b3f7 --- /dev/null +++ b/src/main/java/chess/piece/Queen.java @@ -0,0 +1,154 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public class Queen extends AbstractPiece { + public Queen(Color color, Position position) { + super("Q", color, position); + } + + @Override + public Queen moveTo(Position destination) { + return new Queen(getColor(), destination); + } + + @Override + public boolean isMovableTo(Position destination, final Map positions) { + if (canMoveUp(getPosition(), destination, positions)) { + return true; + } + if (canMoveDown(getPosition(), destination, positions)) { + return true; + } + if (canMoveLeft(getPosition(), destination, positions)) { + return true; + } + if (canMoveRight(getPosition(), destination, positions)) { + return true; + } + if (canMoveLeftUp(getPosition(), destination, positions)) { + return true; + } + if (canMoveLeftDown(getPosition(), destination, positions)) { + return true; + } + if (canMoveRightUp(getPosition(), destination, positions)) { + return true; + } + return canMoveRightDown(getPosition(), destination, positions); + } + + private boolean canMoveUp(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveUp()) { + target = target.moveUp(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveDown(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveDown()) { + target = target.moveDown(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveLeft(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveLeft()) { + target = target.moveLeft(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveRight(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveRight()) { + target = target.moveRight(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveLeftUp(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveLeftUp()) { + target = target.moveLeftUp(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveLeftDown(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveLeftDown()) { + target = target.moveLeftDown(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveRightUp(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveRightUp()) { + target = target.moveRightUp(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveRightDown(Position position, Position destination, Map positions) { + Position target = position; + while (target.canMoveRightDown()) { + target = target.moveRightDown(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } +} diff --git a/src/main/java/chess/piece/Rook.java b/src/main/java/chess/piece/Rook.java new file mode 100644 index 00000000000..be81ce87ff6 --- /dev/null +++ b/src/main/java/chess/piece/Rook.java @@ -0,0 +1,87 @@ +package chess.piece; + +import chess.Color; +import chess.Position; +import java.util.Map; + +public class Rook extends AbstractPiece { + + public Rook(Color color, Position position) { + super("R", color, position); + } + + @Override + public Rook moveTo(Position destination) { + return new Rook(getColor(), destination); + } + + @Override + public boolean isMovableTo(Position destination, final Map positions) { + if (canMoveUp(getPosition(), destination, positions)) { + return true; + } + if (canMoveDown(getPosition(), destination, positions)) { + return true; + } + if (canMoveLeft(getPosition(), destination, positions)) { + return true; + } + return canMoveRight(getPosition(), destination, positions); + } + + private boolean canMoveUp(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveUp()) { + target = target.moveUp(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveDown(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveDown()) { + target = target.moveDown(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveLeft(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveLeft()) { + target = target.moveLeft(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } + + private boolean canMoveRight(Position position, Position destination, final Map positions) { + Position target = position; + while (target.canMoveRight()) { + target = target.moveRight(); + if (target.equals(destination)) { + if (positions.containsKey(target)) { + System.out.println("상대팀 말을 잡았습니다."); + } + return true; + } + } + return false; + } +} diff --git a/src/main/java/chess/view/InputView.java b/src/main/java/chess/view/InputView.java new file mode 100644 index 00000000000..626b2a0bcd2 --- /dev/null +++ b/src/main/java/chess/view/InputView.java @@ -0,0 +1,24 @@ +package chess.view; + +import chess.Column; +import chess.Position; +import chess.Row; +import java.util.Scanner; + +public class InputView { + private static final Scanner scanner = new Scanner(System.in); + + public static Position readStartPosition() { + System.out.println("출발 좌표를 입력해주세요.(예: A,8)"); + String input = scanner.nextLine(); + String[] split = input.split(","); + return new Position(Column.valueOf(split[0]), Row.values()[8-Integer.parseInt(split[1])]); + } + + public static Position readEndPosition() { + System.out.println("도착 좌표를 입력해주세요.(예: A,8)"); + String input = scanner.nextLine(); + String[] split = input.split(","); + return new Position(Column.valueOf(split[0]), Row.values()[8-Integer.parseInt(split[1])]); + } +} diff --git a/src/main/java/chess/view/OutputView.java b/src/main/java/chess/view/OutputView.java new file mode 100644 index 00000000000..feecc24b43a --- /dev/null +++ b/src/main/java/chess/view/OutputView.java @@ -0,0 +1,36 @@ +package chess.view; + +import chess.Board; +import chess.Color; +import chess.Column; +import chess.Position; +import chess.Row; +import chess.piece.Piece; + +public class OutputView { + private static final String BLACK = "\u001B[0m"; + private static final String WHITE = "\u001B[37m"; + private static final String RED = "\u001B[31m"; + + public static void printBoard(Board board) { + System.out.print(RED + " A B C D E F G H "); + System.out.println(BLACK); + for (int i = 7; i >= 0; --i) { + System.out.print(RED + (8 - i) + " "); + for (int j = 0; j < 8; ++j) { + Position target = new Position(Column.values()[j], Row.values()[i]); + if (board.hasPieceAt(target)) { + Piece piece = board.getPiece(target); + if (piece.getColor() == Color.BLACK) { + System.out.print(BLACK + piece.getName() + " " + RED); + } else { + System.out.print(WHITE + piece.getName() + " " + RED); + } + } else { + System.out.print("X "); + } + } + System.out.println(BLACK); + } + } +} diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/test/java/chess/ColumnTest.java b/src/test/java/chess/ColumnTest.java new file mode 100644 index 00000000000..e43523240f7 --- /dev/null +++ b/src/test/java/chess/ColumnTest.java @@ -0,0 +1,95 @@ +package chess; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@DisplayName("열") +class ColumnTest { + + @DisplayName("A는 맨 왼쪽이다.") + @Test + void isFarLeft_A() { + assertThat(Column.A.isFarLeft()).isTrue(); + } + + @DisplayName("B는 맨 왼쪽이 아니다.") + @Test + void isFarLeft_B() { + assertThat(Column.B.isFarLeft()).isFalse(); + } + + @DisplayName("H는 맨 오른쪽이다.") + @Test + void isFarRight_H() { + assertThat(Column.H.isFarRight()).isTrue(); + } + + @DisplayName("F는 맨 오른쪽이 아니다.") + @Test + void isFarRight_F() { + assertThat(Column.F.isFarRight()).isFalse(); + } + + @DisplayName("A는 왼쪽으로 이동할 수 없다.") + @Test + void moveLeft_A() { + assertThatThrownBy(Column.A::moveLeft) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("B는 왼쪽으로 이동하면 A다.") + @Test + void moveLeft_B() { + final var moved = Column.B.moveLeft(); + + assertThat(moved).isEqualTo(Column.A); + } + + @DisplayName("B는 왼쪽으로 2번 이동할 수 없다.") + @Test + void moveLeft_2_B() { + assertThatThrownBy(() -> Column.B.moveLeft(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("C는 왼쪽으로 2번 이동하면 A다.") + @Test + void moveLeft_2_C() { + final var moved = Column.C.moveLeft(2); + + assertThat(moved).isEqualTo(Column.A); + } + + @DisplayName("H는 오른쪽으로 이동할 수 없다.") + @Test + void moveRight_H() { + assertThatThrownBy(Column.H::moveRight) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("G는 오른쪽으로 이동하면 H다.") + @Test + void moveRight_G() { + final var moved = Column.G.moveRight(); + + assertThat(moved).isEqualTo(Column.H); + } + + @DisplayName("G는 오른쪽으로 2번 이동할 수 없다.") + @Test + void moveRight_2_G() { + assertThatThrownBy(() -> Column.G.moveRight(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("F는 오른쪽으로 2번 이동하면 H다.") + @Test + void moveRight_2_F() { + final var moved = Column.F.moveRight(2); + + assertThat(moved).isEqualTo(Column.H); + } +} diff --git a/src/test/java/chess/Fixtures.java b/src/test/java/chess/Fixtures.java new file mode 100644 index 00000000000..f940ab37137 --- /dev/null +++ b/src/test/java/chess/Fixtures.java @@ -0,0 +1,80 @@ +package chess; + +@SuppressWarnings("unused") +public final class Fixtures { + + public static final Position A1 = new Position(Column.A, Row.ONE); + public static final Position A2 = new Position(Column.A, Row.TWO); + public static final Position A3 = new Position(Column.A, Row.THREE); + public static final Position A4 = new Position(Column.A, Row.FOUR); + public static final Position A5 = new Position(Column.A, Row.FIVE); + public static final Position A6 = new Position(Column.A, Row.SIX); + public static final Position A7 = new Position(Column.A, Row.SEVEN); + public static final Position A8 = new Position(Column.A, Row.EIGHT); + + public static final Position B1 = new Position(Column.B, Row.ONE); + public static final Position B2 = new Position(Column.B, Row.TWO); + public static final Position B3 = new Position(Column.B, Row.THREE); + public static final Position B4 = new Position(Column.B, Row.FOUR); + public static final Position B5 = new Position(Column.B, Row.FIVE); + public static final Position B6 = new Position(Column.B, Row.SIX); + public static final Position B7 = new Position(Column.B, Row.SEVEN); + public static final Position B8 = new Position(Column.B, Row.EIGHT); + + public static final Position C1 = new Position(Column.C, Row.ONE); + public static final Position C2 = new Position(Column.C, Row.TWO); + public static final Position C3 = new Position(Column.C, Row.THREE); + public static final Position C4 = new Position(Column.C, Row.FOUR); + public static final Position C5 = new Position(Column.C, Row.FIVE); + public static final Position C6 = new Position(Column.C, Row.SIX); + public static final Position C7 = new Position(Column.C, Row.SEVEN); + public static final Position C8 = new Position(Column.C, Row.EIGHT); + + public static final Position D1 = new Position(Column.D, Row.ONE); + public static final Position D2 = new Position(Column.D, Row.TWO); + public static final Position D3 = new Position(Column.D, Row.THREE); + public static final Position D4 = new Position(Column.D, Row.FOUR); + public static final Position D5 = new Position(Column.D, Row.FIVE); + public static final Position D6 = new Position(Column.D, Row.SIX); + public static final Position D7 = new Position(Column.D, Row.SEVEN); + public static final Position D8 = new Position(Column.D, Row.EIGHT); + + public static final Position E1 = new Position(Column.E, Row.ONE); + public static final Position E2 = new Position(Column.E, Row.TWO); + public static final Position E3 = new Position(Column.E, Row.THREE); + public static final Position E4 = new Position(Column.E, Row.FOUR); + public static final Position E5 = new Position(Column.E, Row.FIVE); + public static final Position E6 = new Position(Column.E, Row.SIX); + public static final Position E7 = new Position(Column.E, Row.SEVEN); + public static final Position E8 = new Position(Column.E, Row.EIGHT); + + public static final Position F1 = new Position(Column.F, Row.ONE); + public static final Position F2 = new Position(Column.F, Row.TWO); + public static final Position F3 = new Position(Column.F, Row.THREE); + public static final Position F4 = new Position(Column.F, Row.FOUR); + public static final Position F5 = new Position(Column.F, Row.FIVE); + public static final Position F6 = new Position(Column.F, Row.SIX); + public static final Position F7 = new Position(Column.F, Row.SEVEN); + public static final Position F8 = new Position(Column.F, Row.EIGHT); + + public static final Position G1 = new Position(Column.G, Row.ONE); + public static final Position G2 = new Position(Column.G, Row.TWO); + public static final Position G3 = new Position(Column.G, Row.THREE); + public static final Position G4 = new Position(Column.G, Row.FOUR); + public static final Position G5 = new Position(Column.G, Row.FIVE); + public static final Position G6 = new Position(Column.G, Row.SIX); + public static final Position G7 = new Position(Column.G, Row.SEVEN); + public static final Position G8 = new Position(Column.G, Row.EIGHT); + + public static final Position H1 = new Position(Column.H, Row.ONE); + public static final Position H2 = new Position(Column.H, Row.TWO); + public static final Position H3 = new Position(Column.H, Row.THREE); + public static final Position H4 = new Position(Column.H, Row.FOUR); + public static final Position H5 = new Position(Column.H, Row.FIVE); + public static final Position H6 = new Position(Column.H, Row.SIX); + public static final Position H7 = new Position(Column.H, Row.SEVEN); + public static final Position H8 = new Position(Column.H, Row.EIGHT); + + private Fixtures() { + } +} diff --git a/src/test/java/chess/PositionTest.java b/src/test/java/chess/PositionTest.java new file mode 100644 index 00000000000..3ad7cc64084 --- /dev/null +++ b/src/test/java/chess/PositionTest.java @@ -0,0 +1,392 @@ +package chess; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static chess.Fixtures.A1; +import static chess.Fixtures.A2; +import static chess.Fixtures.A3; +import static chess.Fixtures.A6; +import static chess.Fixtures.A7; +import static chess.Fixtures.A8; +import static chess.Fixtures.B1; +import static chess.Fixtures.B2; +import static chess.Fixtures.B3; +import static chess.Fixtures.B7; +import static chess.Fixtures.B8; +import static chess.Fixtures.C1; +import static chess.Fixtures.F1; +import static chess.Fixtures.F8; +import static chess.Fixtures.G1; +import static chess.Fixtures.G2; +import static chess.Fixtures.G6; +import static chess.Fixtures.G7; +import static chess.Fixtures.G8; +import static chess.Fixtures.H1; +import static chess.Fixtures.H2; +import static chess.Fixtures.H7; +import static chess.Fixtures.H8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@DisplayName("위치") +class PositionTest { + + + @DisplayName("A1은 맨 왼쪽이다.") + @Test + void nonFarLeft_A1() { + assertThat(A1.isFarLeft()).isTrue(); + } + + @DisplayName("B1은 맨 왼쪽이 아니다.") + @Test + void nonFarLeft_B1() { + assertThat(B1.isFarLeft()).isFalse(); + } + + @DisplayName("H1은 맨 오른쪽이다.") + @Test + void nonFarRight_H1() { + assertThat(H1.isFarRight()).isTrue(); + } + + @DisplayName("F1은 맨 오른쪽이 아니다.") + @Test + void nonFarRight_F1() { + assertThat(F1.isFarRight()).isFalse(); + } + + @DisplayName("A1은 왼쪽으로 이동할 수 없다.") + @Test + void canMoveLeft_A1() { + assertThat(A1.canMoveLeft()).isFalse(); + } + + @DisplayName("A1은 왼쪽으로 이동할 수 없다.") + @Test + void canMoveLeft_Movement_A1() { + assertThat(A1.canMove(Movement.LEFT)).isFalse(); + } + + @DisplayName("B1은 왼쪽으로 이동할 수 있다.") + @Test + void canMoveLeft_B1() { + assertThat(B1.canMoveLeft()).isTrue(); + } + + @DisplayName("A1은 왼쪽으로 이동하면 예외가 발생한다.") + @Test + void moveLeft_A1() { + assertThatThrownBy(A1::moveLeft) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("B1은 왼쪽으로 이동하면 A1이다.") + @Test + void moveLeft_B1() { + final var moved = B1.moveLeft(); + + assertThat(moved).isEqualTo(A1); + } + + @DisplayName("B1은 왼쪽으로 2번 이동할 수 없다.") + @Test + void canMoveLeft_2_B1() { + assertThat(B1.canMoveLeft(2)).isFalse(); + } + + @DisplayName("B1은 왼쪽으로 2번 이동하면 예외가 발생한다.") + @Test + void moveLeft_2_B1() { + assertThatThrownBy(() -> B1.moveLeft(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("C1은 왼쪽으로 2번 이동하면 A1이다.") + @Test + void moveLeft_C2() { + final var moved = C1.moveLeft(2); + + assertThat(moved).isEqualTo(A1); + } + + @DisplayName("H1은 오른쪽으로 이동할 수 없다.") + @Test + void canMoveRight_H1() { + assertThat(H1.canMoveRight()).isFalse(); + } + + @DisplayName("H1은 오른쪽으로 이동할 수 없다.") + @Test + void canMoveRight_Movement_H1() { + assertThat(H1.canMove(Movement.RIGHT)).isFalse(); + } + + @DisplayName("H1은 오른쪽으로 이동하면 예외가 발생한다.") + @Test + void moveRight_H1() { + assertThatThrownBy(H1::moveRight) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("G1은 오른쪽으로 이동하면 H1다.") + @Test + void moveRight_G1() { + final var moved = G1.moveRight(); + + assertThat(moved).isEqualTo(H1); + } + + @DisplayName("G1은 오른쪽으로 2번 이동할 수 없다.") + @Test + void canMoveRight_2_G1() { + assertThat(G1.canMoveRight(2)).isFalse(); + } + + @DisplayName("G1은 오른쪽으로 2번 이동하면 예외가 발생한다.") + @Test + void moveRight_2_G1() { + assertThatThrownBy(() -> G1.moveRight(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("F1은 오른쪽으로 2번 이동하면 H1이다.") + @Test + void moveRight_2_F1() { + final var moved = F1.moveRight(2); + + assertThat(moved).isEqualTo(H1); + } + + ///// + + @DisplayName("A8은 맨 위다.") + @Test + void nonTop_A8() { + assertThat(A8.isTop()).isTrue(); + } + + @DisplayName("A7은 맨 위가 아니다.") + @Test + void nonTop_7() { + assertThat(A7.isTop()).isFalse(); + } + + @DisplayName("A1은 맨 아래다.") + @Test + void nonBottom_A1() { + assertThat(A1.isBottom()).isTrue(); + } + + @DisplayName("A2는 맨 아래가 아니다.") + @Test + void nonBottom_A2() { + assertThat(A2.isBottom()).isFalse(); + } + + @DisplayName("A8은 위로 이동할 수 없다.") + @Test + void canMoveUp_A8() { + assertThat(A8.canMoveUp()).isFalse(); + } + + @DisplayName("A8은 위로 이동하면 예외가 발생한다.") + @Test + void moveUp_A8() { + assertThatThrownBy(A8::moveUp) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("A7은 위로 이동하면 A8이다.") + @Test + void moveUp_A7() { + final var moved = A7.moveUp(); + + assertThat(moved).isEqualTo(A8); + } + + @DisplayName("A7은 위로 이동하면 A8이다.") + @Test + void moveUp_Movement_A7() { + final var moved = A7.move(Movement.UP); + + assertThat(moved).isEqualTo(A8); + } + + @DisplayName("A7은 위로 2번 이동할 수 없다.") + @Test + void canMoveUp_2_A7() { + assertThat(A7.canMoveUp(2)).isFalse(); + } + + @DisplayName("A7은 위로 2번 이동하면 예외가 발생한다.") + @Test + void moveUp_2_A7() { + assertThatThrownBy(() -> A7.moveUp(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("A6은 위로 2번 이동하면 A8이다.") + @Test + void moveUp_2_A6() { + final var moved = A6.moveUp(2); + + assertThat(moved).isEqualTo(A8); + } + + @DisplayName("A1은 아래로 이동할 수 없다.") + @Test + void canMoveDown_A1() { + assertThat(A1.canMoveDown()).isFalse(); + } + + @DisplayName("A1은 아래로 이동하면 예외가 발생한다.") + @Test + void moveDown_A1() { + assertThatThrownBy(A1::moveDown) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("A2는 아래로 이동하면 A1이다.") + @Test + void moveDown_A2() { + final var moved = A2.moveDown(); + + assertThat(moved).isEqualTo(A1); + } + + @DisplayName("A2는 아래로 2번 이동할 수 없다.") + @Test + void canMoveDown_2_A2() { + assertThat(A2.canMoveDown(2)).isFalse(); + } + + @DisplayName("A2는 아래로 2번 이동하면 예외가 발생한다.") + @Test + void moveDown_2_A2() { + assertThatThrownBy(() -> A2.moveDown(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("A3는 아래로 2번 이동하면 A1이다.") + @Test + void moveDown_2_A3() { + final var moved = A3.moveDown(2); + + assertThat(moved).isEqualTo(A1); + } + + @DisplayName("왼쪽 위 대각선으로 움직이면 예외가 발생한다.") + @MethodSource("immovableLeftUpSource") + @ParameterizedTest(name = "{0}은 왼쪽 위 대각선으로 움직이면 예외가 발생한다.") + void moveLeftUp_immovable(final Position position) { + assertThatThrownBy(position::moveLeftUp) + .isInstanceOf(IllegalStateException.class); + } + + static Stream immovableLeftUpSource() { + final var canMoveLeftPositions = Stream.of(A1, A2, A7, A8); + final var canMoveUpPositions = Stream.of(A8, B8, F8, H8); + + return Stream.concat(canMoveLeftPositions, canMoveUpPositions); + } + + @DisplayName("왼쪽 위 대각선으로 움직인다.") + @MethodSource("movableLeftUpSource") + @ParameterizedTest(name = "{0}을 왼쪽 위 대각선으로 움직인다.") + void moveLeftUp_movable(final Position position) { + assertThatCode(position::moveLeftUp) + .doesNotThrowAnyException(); + } + + static Stream movableLeftUpSource() { + return Stream.of(B2, B3, B7, G1, G2, G6, G7); + } + + @DisplayName("오른쪽 위 대각선으로 움직이면 예외가 발생한다.") + @MethodSource("immovableRightUpSource") + @ParameterizedTest(name = "{0}은 오른쪽 위 대각선으로 움직이면 예외가 발생한다.") + void moveRightUp_immovable(final Position position) { + assertThatThrownBy(position::moveRightUp) + .isInstanceOf(IllegalStateException.class); + } + + static Stream immovableRightUpSource() { + final var canMoveRightPositions = Stream.of(H1, H2, H7, H8); + final var canMoveUpPositions = Stream.of(A8, B8, F8, H8); + + return Stream.concat(canMoveRightPositions, canMoveUpPositions); + } + + @DisplayName("오른쪽 위 대각선으로 움직인다.") + @MethodSource("movableRightUpSource") + @ParameterizedTest(name = "{0}을 왼쪽 위 대각선으로 움직인다.") + void moveRightUp_movable(final Position position) { + assertThatCode(position::moveRightUp) + .doesNotThrowAnyException(); + } + + static Stream movableRightUpSource() { + return Stream.of(B1, B2, B3, B7, A2, A6, A7, G1, G2, G7); + } + + @DisplayName("왼쪽 아래 대각선으로 움직이면 예외가 발생한다.") + @MethodSource("immovableLeftDownSource") + @ParameterizedTest(name = "{0}은 왼쪽 아래 대각선으로 움직이면 예외가 발생한다.") + void moveLeftDown_immovable(final Position position) { + assertThatThrownBy(position::moveLeftDown) + .isInstanceOf(IllegalStateException.class); + } + + static Stream immovableLeftDownSource() { + final var canMoveLeftPositions = Stream.of(A1, A2, A7, A8); + final var canMoveDownPositions = Stream.of(A1, B1, F1, H1); + + return Stream.concat(canMoveLeftPositions, canMoveDownPositions); + } + + @DisplayName("왼쪽 아래 대각선으로 움직인다.") + @MethodSource("movableLeftDownSource") + @ParameterizedTest(name = "{0}을 왼쪽 아래 대각선으로 움직인다.") + void moveLeftDown_movable(final Position position) { + assertThatCode(position::moveLeftDown) + .doesNotThrowAnyException(); + } + + static Stream movableLeftDownSource() { + return Stream.of(B2, B3, B7, G8, G2, G6, G7); + } + + @DisplayName("오른쪽 아래 대각선으로 움직이면 예외가 발생한다.") + @MethodSource("immovableRightDownSource") + @ParameterizedTest(name = "{0}은 오른쪽 아래 대각선으로 움직이면 예외가 발생한다.") + void moveRightDown_immovable(final Position position) { + assertThatThrownBy(position::moveRightDown) + .isInstanceOf(IllegalStateException.class); + } + + static Stream immovableRightDownSource() { + final var canMoveRightPositions = Stream.of(H1, H2, H7, H8); + final var canMoveDownPositions = Stream.of(A1, B1, F1, H1); + + return Stream.concat(canMoveRightPositions, canMoveDownPositions); + } + + @DisplayName("오른쪽 아래 대각선으로 움직인다.") + @MethodSource("movableRightDownSource") + @ParameterizedTest(name = "{0}을 왼쪽 아래 대각선으로 움직인다.") + void moveRightDown_movable(final Position position) { + assertThatCode(position::moveRightDown) + .doesNotThrowAnyException(); + } + + static Stream movableRightDownSource() { + return Stream.of(B8, B2, B3, B7, A2, A6, A7, G8, G2, G7); + } +} diff --git a/src/test/java/chess/RowTest.java b/src/test/java/chess/RowTest.java new file mode 100644 index 00000000000..fcb65485410 --- /dev/null +++ b/src/test/java/chess/RowTest.java @@ -0,0 +1,95 @@ +package chess; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@DisplayName("행") +class RowTest { + + @DisplayName("8은 맨 위다.") + @Test + void isTop_8() { + assertThat(Row.EIGHT.isTop()).isTrue(); + } + + @DisplayName("7은 맨 위가 아니다.") + @Test + void isTop_7() { + assertThat(Row.SEVEN.isTop()).isFalse(); + } + + @DisplayName("1은 맨 아래다.") + @Test + void isBottom_1() { + assertThat(Row.ONE.isBottom()).isTrue(); + } + + @DisplayName("2는 맨 아래가 아니다.") + @Test + void isBottom_2() { + assertThat(Row.TWO.isBottom()).isFalse(); + } + + @DisplayName("8은 위로 이동할 수 없다.") + @Test + void moveUp_8() { + assertThatThrownBy(Row.EIGHT::moveUp) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("7은 위로 이동하면 8이다.") + @Test + void moveUp_7() { + final var moved = Row.SEVEN.moveUp(); + + assertThat(moved).isEqualTo(Row.EIGHT); + } + + @DisplayName("7은 위로 2번 이동할 수 없다.") + @Test + void moveUp_2_7() { + assertThatThrownBy(() -> Row.SEVEN.moveUp(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("6은 위로 2번 이동하면 8이다.") + @Test + void moveUp_2_6() { + final var moved = Row.SIX.moveUp(2); + + assertThat(moved).isEqualTo(Row.EIGHT); + } + + @DisplayName("1은 아래로 이동할 수 없다.") + @Test + void moveDown_1() { + assertThatThrownBy(Row.ONE::moveDown) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("2는 아래로 이동하면 1이다.") + @Test + void moveDown_2() { + final var moved = Row.TWO.moveDown(); + + assertThat(moved).isEqualTo(Row.ONE); + } + + @DisplayName("2는 아래로 2번 이동할 수 없다.") + @Test + void moveDown_2_2() { + assertThatThrownBy(() -> Row.TWO.moveDown(2)) + .isInstanceOf(IllegalStateException.class); + } + + @DisplayName("3은 아래로 2번 이동하면 1이다.") + @Test + void moveDown_2_3() { + final var moved = Row.THREE.moveDown(2); + + assertThat(moved).isEqualTo(Row.ONE); + } +}