Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1, 2단계 - 체스] 몰리(김지민) 미션 제출합니다. #661

Merged
merged 92 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
3bd8333
docs: 요구사항 명세서 작성
jminkkk Mar 19, 2024
f628a27
feat: 가로, 세로 좌표값을 가지는 위치 객체 생성
jminkkk Mar 19, 2024
888aeae
feat: 가로, 세로 좌표값을 가지는 위치 객체 생성
jminkkk Mar 19, 2024
174f94d
feat: 열을 1 증가하는 상 방향 구현
jminkkk Mar 19, 2024
d2f4226
feat: 열을 1 감소하는 하 방향 구현
jminkkk Mar 19, 2024
2bb2ad8
feat: 행을 1 감소하는 왼쪽 방향 구현
jminkkk Mar 19, 2024
6b94270
feat: 행을 1 증가하는 오른쪽 방향 구현
jminkkk Mar 19, 2024
f5dae7b
feat: 위치가 경계값인지 확인하는 기능 구현
jminkkk Mar 19, 2024
c052869
feat: 상 방향은 row의 값이 최대일 경우 반환하지 않는 기능 구현
jminkkk Mar 19, 2024
98af828
feat: 하 방향은 row의 값을 최소일 경우 반환하지 않는 기능 구현
jminkkk Mar 19, 2024
222addf
feat: 좌 방향은 column 값을 최소일 경우 반환하지 않는 기능 구현
jminkkk Mar 19, 2024
edec489
feat: 우 방향은 column 값을 최대일 경우 반환하지 않는 기능 구현
jminkkk Mar 19, 2024
7333410
feat: 대각선 상좌 방향은 row 값이 최대이거나 column의 값이 최소일 경우 반환하지 않는 기능 구현
jminkkk Mar 19, 2024
56a19f3
docs: 방향에 대한 책임 변경
jminkkk Mar 19, 2024
b4b8aee
feat: 좌 방향에 대한 기능 구현
jminkkk Mar 19, 2024
2b41062
feat: 상 방향에 대한 기능 구현
jminkkk Mar 19, 2024
f5af6aa
feat: 하 방향에 대한 기능 구현
jminkkk Mar 19, 2024
ac0b7b6
feat: 우 방향에 대한 기능 구현
jminkkk Mar 19, 2024
6dcb504
feat: 대각선 상우 방향에 대한 기능 구현
jminkkk Mar 19, 2024
1e0f5ef
feat: 대각선 상좌 방향에 대한 기능 구현
jminkkk Mar 19, 2024
3d2036d
feat: 대각선 하좌 방향에 대한 기능 구현
jminkkk Mar 19, 2024
e130b53
feat: 대각선 하우 방향에 대한 기능 구현
jminkkk Mar 19, 2024
287d80a
refactor: Direction을 인터페이스로 변경 및 StraightDirection 추상 클래스 구현
jminkkk Mar 20, 2024
725dd43
feat: 나이트 방향에 대한 기능 구현
jminkkk Mar 20, 2024
1a80db6
feat: 색깔 정책에 대한 기능 구현
jminkkk Mar 20, 2024
1fc553a
feat: 첫 이동 여부 정책에 대한 기능 구현
jminkkk Mar 20, 2024
dd659d3
feat: 해당 위치의 적 유무 정책에 대한 기능 구현
jminkkk Mar 20, 2024
62d8c31
feat: 조합한 정책에 대한 객체 구현
jminkkk Mar 20, 2024
87bb3ef
refactor: movement 패키지 아래로 direction 및 policy 이동
jminkkk Mar 20, 2024
f9ab6ca
fix: direction의 생성자를 public으로 변경
jminkkk Mar 20, 2024
6593720
feat: 이동은 방향과 정책으로 생성하는 기능 구현
jminkkk Mar 20, 2024
115b576
feat: 이동이 가지고 있는 정책 조건이 만족하는지 확인하는 기능 구현
jminkkk Mar 20, 2024
cbc9f84
feat: 이동이 가지고 있는 방향을 반환하는 기능 구현
jminkkk Mar 20, 2024
4103808
feat: 제약이 없는 정책에 대한 기능 구현
jminkkk Mar 20, 2024
74e7a25
refactor: KnightDirection 클래스의 접근제한자를 public 으로 변경
jminkkk Mar 20, 2024
dd9de51
feat: 이동 조건 목록을 가지는 말 종류 구현
jminkkk Mar 20, 2024
b15e907
fix: 이동은 다음 위치부터 판단하도록 수정
jminkkk Mar 20, 2024
9ab3b3b
feat: 폰이 이동이 가능한 경우에 대한 기능 구현
jminkkk Mar 20, 2024
5cd5d1e
test: 폰이 이동이 불가능한 경우에 대한 테스트 작성
jminkkk Mar 20, 2024
45654f3
test: 나이트에 이동이 가능/불가능한 경우에 대한 테스트 작성
jminkkk Mar 20, 2024
52358ae
test: 비숍 이동이 가능/불가능한 경우에 대한 테스트 작성
jminkkk Mar 20, 2024
7883f1b
test: 비숍 이동이 가능/불가능한 경우에 대한 테스트 추가
jminkkk Mar 20, 2024
e9df01f
test: 룩이 이동이 가능/불가능한 경우에 대한 테스트 작성
jminkkk Mar 20, 2024
110334e
test: 퀸이 이동이 가능/불가능한 경우에 대한 테스트 작성
jminkkk Mar 20, 2024
aeb4c36
test: 킹이 이동이 가능/불가능한 경우에 대한 테스트 작성
jminkkk Mar 20, 2024
f5c6bcc
refactor: 디버깅 메시지 함수 제거
jminkkk Mar 20, 2024
5904a15
feat: 기물의 초기 위치정보를 담는 객체 구현
jminkkk Mar 20, 2024
dcc7c10
feat: InitialPiecePosition에 기물이 없는 경우 Empty 타입의 말을 넣는 기능 추가
jminkkk Mar 21, 2024
4818cd9
feat: 말을 이동시킬 수 있는 보드 구현
jminkkk Mar 21, 2024
b0f11b1
feat: 사용자 입력 기능 구현
jminkkk Mar 21, 2024
1595a77
feat: 출력 기능 구현
jminkkk Mar 21, 2024
6ab7552
feat: 체스게임 컨트롤러 구현
jminkkk Mar 21, 2024
921fa1f
refactor: Position의 row, column 순서 변경 및 도메인 용어로 이름 변경
jminkkk Mar 21, 2024
736b8f7
refactor: 보드에 초기 말들을 넣어주는 객체 이름을 명확하게 변경
jminkkk Mar 21, 2024
4c89dc9
refactor: 관련있는 패키지끼리 응집
jminkkk Mar 21, 2024
d569200
refactor: 장애물 목록을 찾는 메서드를 작게 분리
jminkkk Mar 21, 2024
15e4f44
refactor: 입력된 말의 위치를 좌표값으로 반환하도록 수정
jminkkk Mar 21, 2024
8d12fbc
refactor: from, to 를 source, target으로 이름 변경 및 컨벤션에 맞춰 수정
jminkkk Mar 21, 2024
1623bd4
style: 해결된 TODO 제거
jminkkk Mar 21, 2024
9cc8332
refactor: 의미없는 조건 제거
jminkkk Mar 21, 2024
2b29bf0
fix: 이동 경로에 아무것도 없을 경우 빈 타입의 말을 반환하도록 수정
jminkkk Mar 21, 2024
afe3a5c
refactor: 다음 경로가 범위안에 있는지 확인하는 로직 분리
jminkkk Mar 21, 2024
caa8f39
fix: 도착 위치에 아무것도 없는 경우 빈 타입의 말을 반환하도록 수정
jminkkk Mar 21, 2024
92e1857
refactor(Application): 예외 발생 시 메시지 출력하도록 수정
jminkkk Mar 22, 2024
aac8325
refactor: 이동에 대한 메서드 로직 수정 및 이동하는 메서드 추출
jminkkk Mar 24, 2024
cc29565
refactor: 공백 Piece를 캐싱하여 재활용하도록 수정
jminkkk Mar 24, 2024
427be33
refactor: 같은 색인지 확인하는 메서드를, 색상에게 같은 팀인지 묻는 메서드로 변경
jminkkk Mar 24, 2024
cb24aa9
refactor: piece를 record로 변경
jminkkk Mar 24, 2024
7421f19
refactor: 기물별 초기 위치를 담고 있는 enum 생성 및 보드 초기화 로직 변경
jminkkk Mar 24, 2024
33da2ea
refactor: 현재 위치로부터 이동거리를 나타내는 방식을 Point클래스에서 MoveDistance로 변경 및 테스트 코…
jminkkk Mar 24, 2024
1325483
refactor: PointConverter의 위치 변경 및 View에서 Point를 반환하도록 수정
jminkkk Mar 24, 2024
ee3efa6
refactor: Position의 file, rank를 각각 enum 객체로 감싸기
jminkkk Mar 24, 2024
7828874
fix: 재시작 후 이동 시 보드판이 초기화되지 않는 문제 해결
jminkkk Mar 25, 2024
a3aa32d
refactor: PointConverter 클래스의 상수 추출
jminkkk Mar 25, 2024
88f812b
refactor: 컨트롤러 실행 로직 변경
jminkkk Mar 26, 2024
4c9e77c
refactor: 위치에 대한 테스트를 위해 픽스처 생성
jminkkk Mar 26, 2024
d8adcd8
refactor: FirstMovePolicy를 PawnFirstMovePolicy로 변경 및 외부에서 첫 이동을 체크하는 …
jminkkk Mar 26, 2024
1513d55
refactor: 메서드 인자에 final 키워드 추가 및 불필요한 변수 생성 제거
jminkkk Mar 26, 2024
6dcec95
refactor: MoveDistance 패키지를 position 아래로 수정
jminkkk Mar 27, 2024
6c3381b
refactor: playTurn 에서 재시작을 체크하는 로직 분리
jminkkk Mar 27, 2024
2a7bd51
refactor: PositionFixture를 fixture 패키지 아래로 이동
jminkkk Mar 27, 2024
43e2071
test: 테스트용 Piece 픽스처 생성
jminkkk Mar 27, 2024
f055448
feat: 장애물 판단 로직을 가지고 있는 추상 클래스 생성
jminkkk Mar 27, 2024
72ed551
refactor: 직선 공격에 대한 장애물 규칙 생성
jminkkk Mar 27, 2024
914a2e7
refactor: 대각선 공격에 대한 장애물 규칙 생성
jminkkk Mar 27, 2024
5d9fb95
refactor: 공격이 없는 경우에 대한 장애물 규칙 생성
jminkkk Mar 27, 2024
56d9e7e
refactor: 위치 간 대각선인지를 확인하는 기능 구현
jminkkk Mar 27, 2024
1a477fd
refactor: 장애물 목록을 찾는 로직 분리
jminkkk Mar 27, 2024
937cfe9
fix: 이동 가능 여부 확인 시 누락된 위치별 피스 Map에 시작 위치, 도착 위치 등 추가
jminkkk Mar 27, 2024
3c1cc35
refactor: 테스트 이해하기 쉽게 수정
jminkkk Mar 27, 2024
8d6fb89
refactor: ObstacleRule 구현체 간 네이밍을 통일성 있게 수정
jminkkk Mar 27, 2024
0da2996
docs: 요구사항 명세에 장애물 규칙 부분 추가
jminkkk Mar 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
117 changes: 117 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# 기능 요구사항 해석

## 초기 기물 정보

- [x] 초기 기물 정보는 각 말들의 시작위치와 말의 종류를 가진다.
- [x] 위치에 기물이 없는 경우 Empty 타입의 말을 넣는다.

## 보드

- [x] 보드는 체스 말과 위치를 가진다.
- [x] 보드에서 체스 말을 이동시킬 수 있다.
- [x] 보드에서 체스 말을 이동할 수 없는 경우 예외가 발생한다.
- [x] 체스 말과 위치 정보를 반환할 수 있다.

## 체스 말

- [x] 체스 말은 진영의 색깔과 종류를 가진다.
- [x] 체스 말은 출발 위치, 도착 위치, 첫 이동 여부, 말의 위치 정보 목록을 바탕으로 움직일 수 있는지 확인한다.
- [x] 폰
- [x] 이동이 가능한 경우
- [x] 수직 이동
- [x] 대각선 이동
- [x] 이동이 불가능 한 경우
- [x] 수직 이동
- [x] 대각선 이동
- [x] 이동이 가능한 경우
- [x] 나이트
- [x] 퀸
- [x] 비숍
- [x] 룩
- [x] 킹
- [x] 이동이 불가능한 경우
- [x] 나이트
- [x] 퀸
- [x] 비숍
- [x] 룩
- [x] 킹

## 말 종류

- [x] 체스 말은 이동을 가진다.

## 이동

- [x] 이동은 이동 방향과 정책을 가진다.
- [x] 이동은 가지고 있는 정책 조건이 만족하는지 확인한다.
- [x] 이동은 가지고 있는 방향을 반환한다.

## 정책

- [x] 이동 정책은 색깔, 첫 이동 여부, 해당 위치의 적 유무에 따른 조건을 가진다.
- [x] 색깔 정책
- [x] 첫 이동 여부 정책
- [x] 해당 위치의 적 유무 정책
- [x] 제약이 없는 정책
- [x] 여러 정책을 조합할 수 있다.

## 방향

- [x] 시작 위치와 도착 위치가 주어지면 해당 방향으로 이동할 수 있는지 확인한다.
- [x] 도착위치 중간에 장애물이 있을 경우 거짓을 반환한다.
- [x] 이동할 수 있는 방향의 개수를 모두 소진함에도 불구하고 도달하지 못할 경우 거짓을 반환한다.
- [x] 방향은 상하좌우, 대각선, 나이트방향으로 이동한다.
- [x] 상 방향
- [x] 하 방향
- [x] 좌 방향
- [x] 우 방향
- [x] 대각선 상좌 방향
- [x] 대각선 상우 방향
- [x] 대각선 하좌 방향
- [x] 대각선 하우 방향
- [x] 나이트 방향
- [x] 방향을 조합하여 여러 위치 정보들을 반환할 수 있다.
Comment on lines +58 to +73
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼼꼼한 요구사항 정의 💯


## 위치

- [x] 위치는 세로(File), 가로(Rank) 좌표값을 가진다.
- [x] 위치의 가로, 세로 범위는 각각 1 ~ 8 이다.
- [x] 위치가 경계 값인지 확인한다.
- [x] Rank값이 최소인지 확인한다.
- [x] Rank값이 최대인지 확인한다.
- [x] File값이 최소인지 확인한다.
- [x] File값이 최대인지 확인한다.

## 장애물 규칙

### 공격 공통

- [x] EMPTY가 아닌 Piece들의 위치 목록 조회
- [x] 목표 위치가 상대편 말일 경우, 공격할 수 있기 때문에 장애물 목록에서 제거
- [x] 출발 위치는 현재 자신의 위치이므로, 장애물 목록에서 제거

### 대각선 공격 시 (공격 공통 + 추가)

아래의 경우에 장애물 목록에 도착 위치 Piece를 추가한다.

- [x] 도착 위치가 상대편 말이지만 출발 위치와 도착 위치가 직선 이동일 경우
- [x] 도착 위치가 EMPTY이고 출발 위치와 도착 위치가 대각 이동일 경우

## 입출력

- [x] 입력 기능 구현
- [x] 명령어 정의 및 입력 구현
- [x] 위치 정보 입력 구현

- [x] 출력 기능 구현
- [x] 명령어 도움말 출력
- [x] 체스 보드 출력

## 체스게임 컨트롤러

- [x] 게임 시작 종료
- [x] start는 보드를 초기화하고 시작한다.
- [x] end는 게임을 종료한다.
- [x] move 기능 구현
- [x] 이동 위치를 입력 받는다.

16 changes: 16 additions & 0 deletions src/main/java/chess/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package chess;

import chess.controller.ChessGameController;
import chess.view.InputView;
import chess.view.OutputView;

public class Application {
public static void main(String[] args) {
try {
ChessGameController chessGameController = new ChessGameController(new InputView(), new OutputView());
chessGameController.start();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}
}
}
61 changes: 61 additions & 0 deletions src/main/java/chess/controller/ChessGameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package chess.controller;

import chess.domain.board.Board;
import chess.domain.board.BoardInitializer;
import chess.domain.position.Position;
import chess.view.GameCommand;
import chess.view.InputView;
import chess.view.OutputView;

public class ChessGameController {

private final OutputView outputView;
private final InputView inputView;

public ChessGameController(final InputView inputView, final OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public void start() {
outputView.printInitialMessage();
GameCommand gameCommand = inputView.getGameCommand();
checkStart(gameCommand);

play();
}

private void checkStart(final GameCommand gameCommand) {
if (gameCommand != GameCommand.START) {
throw new IllegalArgumentException("시작 명령어를 입력해주세요.");
}
}

private void play() {
Board board = initializeBoard();
GameCommand gameCommand = inputView.getGameCommand();

while (gameCommand == GameCommand.MOVE) {
playTurn(board);
gameCommand = inputView.getGameCommand();
}

if (gameCommand == GameCommand.START) {
play();
}
}

private Board initializeBoard() {
Board board = new Board(new BoardInitializer());
outputView.printBoard(board);
return board;
}

private void playTurn(final Board board) {
Position source = Position.of(inputView.getPosition());
Position target = Position.of(inputView.getPosition());

board.tryMove(source, target);
outputView.printBoard(board);
}
}
36 changes: 36 additions & 0 deletions src/main/java/chess/domain/board/Board.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package chess.domain.board;

import chess.domain.piece.Piece;
import chess.domain.position.Position;
import java.util.Collections;
import java.util.Map;

public class Board {

private final BoardInitializer boardInitializer;
private final Map<Position, Piece> board;

public Board(final BoardInitializer boardInitializer) {
this.boardInitializer = boardInitializer;
this.board = boardInitializer.initialize();
}

public void tryMove(final Position source, final Position target) {
Piece piece = board.get(source);
if (piece.canMove(source, target, getBoard())) {
move(source, target, piece);
return;
}

throw new IllegalArgumentException("이동이 불가능한 위치입니다.");
}

private void move(final Position source, final Position target, final Piece piece) {
board.put(target, piece);
board.put(source, Piece.getEmptyPiece());
}

public Map<Position, Piece> getBoard() {
return Collections.unmodifiableMap(board);
}
}
61 changes: 61 additions & 0 deletions src/main/java/chess/domain/board/BoardInitializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package chess.domain.board;

import static chess.domain.piece.Color.BLACK;
import static chess.domain.piece.Color.WHITE;

import chess.domain.piece.Color;
import chess.domain.piece.Piece;
import chess.domain.position.Position;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class BoardInitializer {

private static final int MINIMUM_BOARD_POSITION = 1;
private static final int MAXIMUM_BOARD_POSITION = 8;

private final Map<Position, Piece> initialPiecePositions;

public BoardInitializer() {
Map<Position, Piece> initialPiecePositions = generateEmptyBoard();
initialPiecePositions.putAll(getPiecesByColor(WHITE));
initialPiecePositions.putAll(getPiecesByColor(BLACK));
this.initialPiecePositions = initialPiecePositions;
}

public Map<Position, Piece> initialize() {
return new HashMap<>(initialPiecePositions);
}

private Map<Position, Piece> generateEmptyBoard() {
return IntStream.rangeClosed(MINIMUM_BOARD_POSITION, MAXIMUM_BOARD_POSITION)
.boxed()
.flatMap(this::generateHorizontalLine)
.collect(generateEntry(Piece.getEmptyPiece()));
}

private Stream<Position> generateHorizontalLine(final int rank) {
return IntStream.rangeClosed(MINIMUM_BOARD_POSITION, MAXIMUM_BOARD_POSITION)
.mapToObj(file -> Position.of(file, rank));
}

private Collector<Position, ?, Map<Position, Piece>> generateEntry(final Piece piece) {
return Collectors.toMap(
position -> position,
position -> piece
);
}

private Map<Position, Piece> getPiecesByColor(final Color color) {
List<InitialPiecePosition> whitePieces = InitialPiecePosition.getInitialPositionByColor(color);
return whitePieces.stream()
.flatMap(initialPiecePosition -> initialPiecePosition.getInitialPositions().stream()
.collect(generateEntry(initialPiecePosition.getPiece())).entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (existing, replacement) -> existing));
}
}
88 changes: 88 additions & 0 deletions src/main/java/chess/domain/board/InitialPiecePosition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package chess.domain.board;

import chess.domain.piece.Color;
import chess.domain.piece.Piece;
import chess.domain.piece.PieceType;
import chess.domain.position.Position;
import java.util.Arrays;
import java.util.List;

public enum InitialPiecePosition {
BLACK_KING(new Piece(PieceType.KING, Color.BLACK), List.of(Position.of(5, 8))),
WHITE_KING(new Piece(PieceType.KING, Color.WHITE), List.of(Position.of(5, 1))),

Comment on lines +10 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

따라서 이번 리팩토링에서 File과 Rank를 enum으로 감싸면서, Position 자체도 enum으로 구현할 수 있겠는데? 하는 생각이 들었는데요.
하지만, 변경이 될 가능성을 아예 없는가?에 대한 생각에서는 확신할 수 없었어요.

👍 좋은 고민입니다!! 당연히
몰리도 잘 아시겠지만, 결론은 "우리 비즈니스(사업) 특성이 어떤가?" 를 파악하고,
그걸 기반으로 설계를 한다... 입니다.

만약 몰리와 함께하는 팀원(특히 기획자나 PO)들이
"앞으로 저희 체스 게임은 좌표 입력 방식을 더 사용자 친화적으로 바꿀거에요." 라는 이야기를 던져두었다면,
몰리는 그 이야기를 귀기울여두었다가 변경이 쉽도록 현재와 같은 설계를 할 수 있겠죠.
그렇지 않다면 잘 변하지 않으므로 몰리의 아이디어처럼 enum 으로 구현해버릴 수도 있구요.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사업에 관심을 갖고 귀 기울이는 것은 단순히 애정의 영역을 넘어, 일을 잘하는 것과도 관계가 있을텐데요,
만약 사업의 특성을 잘 모르면 혼자만의 설계에 심취하여 변경될 일이 전무한 엄한 부분을 설계하느라 시간을 허비할 수도 있겠죠.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하! 상황에 맞게 적절하게 고려하는 것이 역시 중요한 것 같네요...!
의견 감사합니다 현구막 👍

BLACK_QUEEN(new Piece(PieceType.QUEEN, Color.BLACK), List.of(Position.of(4, 8))),
WHITE_QUEEN(new Piece(PieceType.QUEEN, Color.WHITE), List.of(Position.of(4, 1))),

BLACK_BISHOP(new Piece(PieceType.BISHOP, Color.BLACK), List.of(
Position.of(3, 8),
Position.of(6, 8))),
WHITE_BISHOP(new Piece(PieceType.BISHOP, Color.WHITE), List.of(
Position.of(3, 1),
Position.of(6, 1))),

BLACK_ROOK(new Piece(PieceType.ROOK, Color.BLACK), List.of(
Position.of(1, 8),
Position.of(8, 8))),
WHITE_ROOK(new Piece(PieceType.ROOK, Color.WHITE), List.of(
Position.of(1, 1),
Position.of(8, 1))),

BLACK_KNIGHT(new Piece(PieceType.KNIGHT, Color.BLACK), List.of(
Position.of(2, 8),
Position.of(7, 8))),
WHITE_KNIGHT(new Piece(PieceType.KNIGHT, Color.WHITE), List.of(
Position.of(2, 1),
Position.of(7, 1))),

BLACK_PAWN(new Piece(PieceType.PAWN, Color.BLACK), List.of(
Position.of(1, 7),
Position.of(2, 7),
Position.of(3, 7),
Position.of(4, 7),
Position.of(5, 7),
Position.of(6, 7),
Position.of(7, 7),
Position.of(8, 7))),

WHITE_PAWN(new Piece(PieceType.PAWN, Color.WHITE), List.of(
Position.of(1, 2),
Position.of(2, 2),
Position.of(3, 2),
Position.of(4, 2),
Position.of(5, 2),
Position.of(6, 2),
Position.of(7, 2),
Position.of(8, 2)));

private final Piece piece;
private final List<Position> initialPositions;

InitialPiecePosition(final Piece piece, final List<Position> initialPositions) {
this.piece = piece;
this.initialPositions = initialPositions;
}

public static List<InitialPiecePosition> getInitialPositionByColor(Color color) {
return Arrays.stream(values())
.filter(initialPiecePosition -> initialPiecePosition.isSameColor(color))
.toList();
}

public boolean isSameColor(final Color color) {
return piece.color() == color;
}

public List<Position> getInitialPositions() {
return initialPositions;
}

public Piece getPiece() {
return piece;
}

public boolean isPawnFirstMove(final Position position) {
return piece.pieceType() == PieceType.PAWN &&
initialPositions.contains(position);
}
}
Loading