Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3a12a76
feat: 피스 생성 테스트 및 구현
seongbeenkim Aug 16, 2021
667d30a
feat: 피스 위치 캐싱 테스트 및 구현
seongbeenkim Aug 16, 2021
05e7c1d
feat: 체스판 32개의 피스 초기화, 생성 테스트 및 구현
seongbeenkim Aug 16, 2021
2d33803
feat: 기물 종류에 따라 이름을 매핑하는 기물 이름 매퍼 테스트 및 구현
seongbeenkim Aug 17, 2021
cc54492
feat: 체스판 전체 출력하는 기능 구현
seongbeenkim Aug 17, 2021
8bc0bd5
feat: 체스 게임 시작&종료 명령어 입력 테스트 및 구현
seongbeenkim Aug 17, 2021
f6c2eb4
feat: 기물 이동 시 공통 예외 케이스 테스트 및 구현
seongbeenkim Aug 17, 2021
22d29d1
feat: 비숍 이동 규칙 테스트 및 구현
seongbeenkim Aug 17, 2021
c877ccd
feat: 룩 이동 규칙 테스트 및 구현
seongbeenkim Aug 17, 2021
adc18b6
feat: 퀸 이동 규칙 테스트 및 구현
seongbeenkim Aug 17, 2021
f3c877a
feat: 킹 이동 규칙 테스트 및 구현
seongbeenkim Aug 17, 2021
12da4ca
feat: 나이트 이동 규칙 테스트 및 구현
seongbeenkim Aug 17, 2021
44ecf39
feat: 폰 이동 규칙 테스트 및 구현
seongbeenkim Aug 19, 2021
4498862
feat: 체스판에서 피스 이동 테스트 및 구현
seongbeenkim Aug 19, 2021
a40508d
refactor: 피스 색상별 체스판 분리
seongbeenkim Aug 19, 2021
c30f242
feat: 비숍, 룩 공격 가능한 경로 반환하는 테스트 및 기능 구현
seongbeenkim Aug 19, 2021
483c149
feat: 폰 제외한 기물 패턴 테스트 및 기능 구현
seongbeenkim Aug 20, 2021
c2f0dea
feat: 기물 이동 시 공격 가능 위치를 갱신하는 테스트 및 기능 구현
seongbeenkim Aug 20, 2021
c17c852
feat: 킹 이동제한조건 테스트 및 기능 구현, 예외 처리 및 게임 흐름 제어
jiwoo-kimm Aug 20, 2021
5d69a67
feat: 점수 계산 기능 테스트 및 구현
seongbeenkim Aug 20, 2021
be1d67e
feat: 점수 및 게임 결과 출력 기능 구현
jiwoo-kimm Aug 20, 2021
aba4a3a
refactor: 패키지 구조 및 테스트 케이스 정리
jiwoo-kimm Aug 20, 2021
0401fb6
feat: 웹 체스 MVC 구조 및 초기화면 세팅
jiwoo-kimm Aug 29, 2021
bdb9729
feat: 기물 이동, 현재 점수, 안내 메시지 출력 구현
jiwoo-kimm Aug 30, 2021
ffec341
feat: 게임 종료, 결과 출력 기능 구현
jiwoo-kimm Aug 31, 2021
8e2830b
refactor: ChessGame 도메인 삭제, ChessService로 통합
jiwoo-kimm Aug 31, 2021
778b8d6
refactor: ChessService의 isGameFinished flag 제거, Status의 isKingDead fl…
jiwoo-kimm Aug 31, 2021
cdc9cda
fix: 퀸 이동 패턴 수정
jiwoo-kimm Sep 3, 2021
a0a341c
refactor: ChessGame 도메인 삭제, ChessService로 통합, 게임종료플래그
jiwoo-kimm Sep 3, 2021
b3770b2
refactor: Controller 역할을 Service, Command, Operation으로 분리
jiwoo-kimm Sep 3, 2021
d97f271
refactor: Board 가독성 개선, 메서드 길이 제한 확인
jiwoo-kimm Sep 3, 2021
cd61bd7
refactor: 기물 이동 리팩토링
jiwoo-kimm Sep 5, 2021
9931625
test: 공격 경로 탐색 테스트 수정
jiwoo-kimm Sep 5, 2021
2026dac
refactor: Player -> Team 으로 명칭 변경
jiwoo-kimm Sep 15, 2021
8a8ccbb
refactor: Team 정적 팩토리 생성자 도입
jiwoo-kimm Sep 15, 2021
ea4b38f
refactor: Board → ChessGame 으로 명칭 변경
jiwoo-kimm Sep 15, 2021
46a6daa
refactor: 기물 이동 메서드 이름 수정
jiwoo-kimm Sep 15, 2021
b574593
refactor: 플레이어의 플레이 순서 관리 추가
jiwoo-kimm Sep 29, 2021
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
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,101 @@
# java-chess 게임

## 구현해야할 목록

- [x] 입력
- [x] 명령어 입력
- [x] 출력
- [x] 시작 안내 문구 출력
- [x] 체스판 전체 출력
- [x] 점수와 결과 출력

- [x] 체스게임(ChessGame)
- [x] 체스판
- [x] 현재 플레이어
- [x] 게임 시작&종료 상태 제어

- 기능
- [x] 명령어 검증 및 처리
- [x] start : 게임 실행
- [x] end : 게임 종료
- [x] move : 인자로 전달받은 source 위치에서 target 위치로 기물 이동

- [x] 체스판(Board)
- [x] 체스판
- [x] 생성 시 32개의 기물 초기화

- 기능
- [x] 인자로 전달받은 위치에 기물이 있는지 확인
- [x] ERROR : 존재하지 않을 경우
- [x] 같은 색상 기물인지 확인
- [x] ERROR : 다른 색상일 경우
- [x] 시작과 도착 위치의 기물이 다른 색상인지 확인
- [x] ERROR : 같은 색상일 경우
- [x] source 위치에서 target 위치로 기물 이동
- [x] ERROR : source 위치에 기물이 없는 경우
- [x] ERROR : 자신의 기물이 아닌 경우
- [x] ERROR : source, target 위치의 기물 색상이 같을 경우
- [x] ERROR : source, target 위치가 같을 경우
- [x] ERROR : 이동 경로에 기물이 존재할 경우

- [x] 기물(Piece)
- [x] 색상

- [x] 기물 위치(Position)
- [x] 파일
- [x] 랭크
- [x] 64개의 캐싱된 위치

- 기능
- [x] 전달받은 인자에 해당하는 위치 객체 반환

- [x] 기물 색상(Color)
- [x] 색상

- [x] 기물 이름 매퍼
- [x] 기물 종류에 따라 이름을 매핑

- [x] 플레이어(Player)
- [x] 자신의 기물
- [x] 자신이 공격 가능한 범위

- 기능
- [x] 기물을 이동시킨다.
- [x] 기물의 이동 경로를 반환한다.
- [x] 입력받은 위치에 기물이 있는지 확인한다.

## 이동 규칙

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

각 기물 뒤에 나온 숫자가 점수인 것으로 보이는데,
점수 계산에 대한 것도 기능 목록으로 빼면 어떨까요?
해당 코드만 보고 이해하는 사람에게는 어떤 숫자를 의미하는지 알기가 어려울 것 같아요.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵! Player 기능목록에 점수 계산도 추가했습니다


- [x] 폰 (1 or 0.5)
- [x] 적 방향 직선 1칸 이동
- [x] ERROR : 직선 방향 2칸 이상일 경우
- [x] ERROR : 좌, 우 이동이 포함될 경우
- [x] 처음 이동 시에는 2칸 이동 가능
- [x] ERROR : 직선 방향 3칸 이상일 경우
- [x] ERROR : 좌, 우 이동이 포함될 경우

- [x] 공격 : 적 방향 좌, 우 대각선 1칸
- [x] ERROR : 직선 1칸 && 좌 또는 우 1칸이 아닐 경우

- [x] 룩 (5)
- [x] 모든 직선 방향으로 원하는 만큼 이동 가능
- [x] ERROR : 룩 이동 패턴으로 이동할 수 없는 위치일 경우

- [x] 나이트 (2.5)
- [x] 모든 직선 방향 1칸 + 이동한 직선 방향의 좌, 우 대각선 1칸으로 이동 가능
- [x] ERROR : 나이트 이동 패턴으로 이동할 수 없는 위치일 경우
- [x] 진행 방향이 가로막혀도 적, 아군 상관없이 뛰어넘을 수 있다.

- [x] 비숍 (3)
- [x] 모든 대각선 방향으로 원하는 만큼 이동 가능
- [x] ERROR : 비숍 이동 패턴으로 이동할 수 없는 위치일 경우

- [x] 퀸 (9)
- [x] 모든 방향 1칸 + α 이동 (모든 대각선 방향으로는 원하는 만큼 이동 가능)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

퀸의 이동방향은 상하좌우대각선 모두 원하는만큼 이동인 것으로 알고 있는데,
상하좌우는 1칸씩밖에 이동하지 못하는건가요?
퀸의 이동 규칙을 한 번 다시 봐주시겠어요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵 퀸 이동 규칙을 완전히 착각해버렸어요ㅠㅠ 수정했습니다!

- [x] ERROR : 퀸 이동 패턴으로 이동할 수 없는 위치일 경우

- [x] 킹
- [x] 모든 방향 1칸 이동
- [x] ERROR : 킹 이동 패턴으로 이동할 수 없는 위치일 경우
- [x] 상대의 공격 범위로는 이동 불가능

1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
testCompile "org.assertj:assertj-core:3.14.0"
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2'
}
17 changes: 17 additions & 0 deletions src/main/java/chess/ConsoleApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package chess;

import chess.controller.ChessController;
import chess.view.ConsoleInputView;
import chess.view.ConsoleOutputView;
import chess.view.InputView;
import chess.view.OutputView;

public class ConsoleApplication {

public static void main(String[] args) {
OutputView outputView = new ConsoleOutputView();
InputView inputView = new ConsoleInputView();
ChessController chessController = new ChessController(inputView, outputView);
chessController.run();
}
}
76 changes: 76 additions & 0 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package chess.controller;

import chess.controller.dto.BoardDto;
import chess.domain.ChessGame;
import chess.domain.board.Status;
import chess.domain.command.Command;
import chess.view.InputView;
import chess.view.OutputView;

public class ChessController {

private final InputView inputView;
private final OutputView outputView;

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

public void run() {
outputView.printGuide();
ChessGame chessGame = new ChessGame();

while (chessGame.isRunning()) {
try {
outputView.printTurn(chessGame.isWhiteTurn());
Command command = new Command(inputView.getCommand());
runCommand(chessGame, command);
printBoard(chessGame);
} catch (UnsupportedOperationException e) {
System.out.println(e.getMessage());
}
}

printBoard(chessGame);
printStatus(chessGame);
}

private void runCommand(final ChessGame chessGame, final Command command) {
try {
if (command.isStart()) {
return;
}

if (command.isEnd()) {
chessGame.end();
return;
}

if (command.isMove()) {
chessGame.move(command.getMoveParameters());
return;
}

if (command.isStatus()) {
printStatus(chessGame);
return;
}
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return;
}

throw new UnsupportedOperationException("유효하지 않은 명령어입니다.");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

controller가 너무 많은 역할을 부담하고 있는건 아닐까요?
mvc 패턴에서 컨트롤러의 역할에 대해 고민해보면 좋을 것 같아요!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵! CommandOperation에서 명령어 검증을 수행하도록 분리하고, 유효한 명령어 수행은 ChessService가 수행하도록 수정했습니다!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

근데 제가 status 명령어 입력을 받으면 서비스에서 커스텀예외를 던지고, 컨트롤러가 그것을 받아서 현재 점수를 출력하도록 했는데, 이렇게 하는 것보다 나은 방법이 있을지 궁금합니다!


private void printBoard(final ChessGame chessGame) {
BoardDto boardDto = new BoardDto(chessGame.getBoard());
outputView.printBoard(boardDto);
}

private void printStatus(final ChessGame chessGame) {
Status status = chessGame.getStatus();
outputView.printStatus(status);
}
}
41 changes: 41 additions & 0 deletions src/main/java/chess/controller/dto/BoardDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package chess.controller.dto;

import chess.domain.board.Board;
import chess.domain.board.File;
import chess.domain.board.Rank;
import chess.domain.piece.Piece;
import chess.domain.piece.type.PieceType;
import chess.domain.player.Position;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class BoardDto {
private List<PositionDto> positionDtos = new ArrayList<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

positionsDto를 먼저 초기화 하는 �이유가 있을까요?
해당 클래스로 객체가 생성되는 상황이 아래 생성자 하나뿐인데,
실제 initial 될 때 할당하는 것은 어떨까요?
해당 필드는 출력할 때만 쓰이는 스냅샷이기 때문에 해당 디티오를 변하지 않도록 설계해주면
더 안전한 프로그램이 될 수 있을 것 같아요 :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵! 생성자에서 불변 리스트를 만들도록 수정했습니다


public BoardDto(final Board board) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

borad라는 도메인 객체와 출력을 위한 dto를 분리하는 좋은 방향을 잡으셨네요 👍

Arrays.stream(Rank.values()).forEach(rank -> Arrays.stream(
File.values()).forEach(file -> addPositionDto(file, rank, board)));
}

private void addPositionDto(final File file, final Rank rank, final Board board) {
Position position = Position.from(file, rank);

if (board.isEmpty(position)) {
PositionDto positionDto = new PositionDto(position.getFile());
positionDtos.add(positionDto);
return;
}

Piece piece = board.findBy(position);
String name = PieceType.findNameBy(piece);
PositionDto positionDto = new PositionDto(position.getFile(), name);
positionDtos.add(positionDto);
}

public List<PositionDto> getPositionDtos() {
return Collections.unmodifiableList(positionDtos);
}
}
28 changes: 28 additions & 0 deletions src/main/java/chess/controller/dto/PositionDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package chess.controller.dto;

import chess.domain.board.File;

public class PositionDto {

private static final String DEFAULT_NAME = ".";

private final boolean isLastFile;
private final String name;

public PositionDto(final File file, final String name) {
this.isLastFile = (file == File.h);
this.name = name;
}

public PositionDto(final File file) {
this(file, DEFAULT_NAME);
}

public boolean isLastFile() {
return isLastFile;
}

public String getName() {
return name;
}
}
44 changes: 44 additions & 0 deletions src/main/java/chess/domain/ChessGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package chess.domain;

import chess.domain.board.Board;
import chess.domain.board.Status;
import chess.domain.command.MoveParameters;

public class ChessGame {

private final Board board = new Board();
private boolean isRunning = true;
private boolean isWhiteTurn = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

조금 더 객체지향적으로 가져가보면 어떨까요? 만약 이 게임이 4인용이 되어서 2:2로 팀전을 하면 어떻게 될까요?
turn에 대한 개념의 역할이 boolean 하나로 표현되기에는 조금 더 많은 역할을 하고 있는 것 같아요.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵! 일단 Color 객체로 표현하도록 하고, nextTurn()도 그 안에서 구현하도록 수정했어요
만약 말씀하신대로 팀전같은 기능으로 확장된다면, 그건 컨트롤러 차원에서 사용자ID와 같은 값으로 순서를 제어하지 않을까요!? 보드는 흑백만 알고 있으면 되니까 더 추상화된 객체를 가질 필요가 없다고 생각이 드는데, 혹시 어느 부분을 제가 생각하지 못 한 건지 알려주실 수 있으신가요??


public ChessGame() {
}

public void move(final MoveParameters moveParameters) {
board.move(moveParameters, isWhiteTurn);
isWhiteTurn = !isWhiteTurn;

if (board.isEnd()) {
isRunning = false;
}
}

public void end() {
isRunning = false;
}

public Status getStatus() {
return board.getStatus();
}

public boolean isRunning() {
return isRunning;
}

public Board getBoard() {
return board;
}

public boolean isWhiteTurn() {
return isWhiteTurn;
}
}
Loading