-
Notifications
You must be signed in to change notification settings - Fork 415
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
Changes from all commits
3bd8333
f628a27
888aeae
174f94d
d2f4226
2bb2ad8
6b94270
f5dae7b
c052869
98af828
222addf
edec489
7333410
56a19f3
b4b8aee
2b41062
f5af6aa
ac0b7b6
6dcb504
1e0f5ef
3d2036d
e130b53
287d80a
725dd43
1a80db6
1fc553a
dd659d3
62d8c31
87bb3ef
f9ab6ca
6593720
115b576
cbc9f84
4103808
74e7a25
dd9de51
b15e907
9ab3b3b
5cd5d1e
45654f3
52358ae
7883f1b
e9df01f
110334e
aeb4c36
f5c6bcc
5904a15
dcc7c10
4818cd9
b0f11b1
1595a77
6ab7552
921fa1f
736b8f7
4c89dc9
d569200
15e4f44
8d12fbc
1623bd4
9cc8332
2b29bf0
afe3a5c
caa8f39
92e1857
aac8325
cc29565
427be33
cb24aa9
7421f19
33da2ea
1325483
ee3efa6
7828874
a3aa32d
88f812b
4c9e77c
d8adcd8
1513d55
6dcec95
6c3381b
2a7bd51
43e2071
f055448
72ed551
914a2e7
5d9fb95
56d9e7e
1a477fd
937cfe9
3c1cc35
8d6fb89
0da2996
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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] 방향을 조합하여 여러 위치 정보들을 반환할 수 있다. | ||
|
||
## 위치 | ||
|
||
- [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] 이동 위치를 입력 받는다. | ||
|
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()); | ||
} | ||
} | ||
} |
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); | ||
} | ||
} |
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); | ||
} | ||
} |
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)); | ||
} | ||
} |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
👍 좋은 고민입니다!! 당연히 만약 몰리와 함께하는 팀원(특히 기획자나 PO)들이 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사업에 관심을 갖고 귀 기울이는 것은 단순히 애정의 영역을 넘어, 일을 잘하는 것과도 관계가 있을텐데요, There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
꼼꼼한 요구사항 정의 💯