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

Dazzle Chess #9

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ff4f19d
feat: remove web dependency
woowahan-neo Mar 13, 2023
1bab9ff
feat: add example for functional programming api example
woowahan-neo Mar 13, 2023
98598c0
chore: change package
woowahan-neo Mar 13, 2023
dd30e0c
[1, 2단계 - 체스] 다즐(최우창) 미션 제출합니다. (#488)
woo-chang Mar 21, 2023
5a7910b
refactor: 움직임 여부 결정은 체스 기물이 책임을 다하도록 수정
woo-chang Mar 22, 2023
22049f8
feat: 폰인지 확인하는 기능 구현
woo-chang Mar 22, 2023
fabbd51
feat: 색에 따른 기물 점수 계산 기능 구현
woo-chang Mar 22, 2023
711e7ff
feat: 체스 상태에 따른 결과 출력 기능 구현
woo-chang Mar 22, 2023
a4af8de
refactor: 실행 커멘드를 입력하도록 수정
woo-chang Mar 23, 2023
3b2f0e9
refactor: 상태 패턴을 이용하여 게임을 진행하도록 수정
woo-chang Mar 23, 2023
af28179
fix: 사용되지 않는 파일 삭제
woo-chang Mar 23, 2023
7b6b229
chore: 디렉토리 수정
woo-chang Mar 23, 2023
ba78b82
refactor: PieceType으로 기물을 구분하도록 수정
woo-chang Mar 23, 2023
19bd0bf
refactor: 점수 계산 로직 수정
woo-chang Mar 23, 2023
aeffe72
feat: 왕이 잡히면 게임이 종료되는 기능 구현
woo-chang Mar 23, 2023
89b727d
chore: 디렉토리 수정
woo-chang Mar 23, 2023
a97f34e
feat: db dockerfile 생성
woo-chang Mar 23, 2023
a08a3e0
feat: DB 커넥션 연결 기능 구현
woo-chang Mar 24, 2023
9e56841
feat: 체스 게임 정보 저장 및 목록 조회 기능 구현
woo-chang Mar 24, 2023
0d79279
feat: 체스 기물 저장 및 모든 체스 기물 조회 기능 구현
woo-chang Mar 25, 2023
9317d9c
feat: 파일과 랭크에 해당하는 기물 조회 기능 구현
woo-chang Mar 25, 2023
3275391
feat: 체스 기물의 색과 타입을 수정하는 기능 구현
woo-chang Mar 25, 2023
bc8c020
feat: 체스 기물을 삭제하는 기능 구현
woo-chang Mar 25, 2023
1e2ba1f
refactor: 개행 수정
woo-chang Mar 25, 2023
207136c
feat: 게임 시작과 실행 명령을 분리하도록 기능 구현
woo-chang Mar 25, 2023
8a99632
feat: 체스 게임을 조회하는 기능 구현
woo-chang Mar 25, 2023
7b76567
refactor: 정적 필드 사용하도록 수정
woo-chang Mar 25, 2023
1b86177
feat: 체스 게임과 기물 서비스 레이어 구현
woo-chang Mar 25, 2023
9072197
refactor: 체스 기물 쿼리 시그니처 수정
woo-chang Mar 25, 2023
4e9f828
refactor: 사용되지 않는 게임 상태 삭제
woo-chang Mar 25, 2023
b2aedbe
feat: 체스 게임 수정 및 삭제 기능 구현
woo-chang Mar 25, 2023
0a03229
feat: 체스 기물 삭제 및 모두 삭제 기능 구현
woo-chang Mar 25, 2023
dcb9132
feat: 체스 기물 동작 후 체스 DB 업데이트하는 기능 구현
woo-chang Mar 25, 2023
58fa4cb
docs: 체스 미션 문서 수정
woo-chang Mar 25, 2023
05d7b87
refactor: 가독성을 위한 코드 컨벤션 수정
woo-chang Mar 25, 2023
7684385
refactor: 체스 관련 dao를 하나로 관리하도록 수정
woo-chang Mar 30, 2023
9ca046b
refactor: db 변화, 도메인 변화 흐름이 잘 보이도록 수정
woo-chang Mar 30, 2023
6ba4092
feat: 게임 상태를 저장하는 컬럼 추가
woo-chang Mar 30, 2023
8d1940e
fix: DDL 수정으로 인한 쿼리 수정
woo-chang Mar 30, 2023
07f8018
feat: 왕이 잡혀 게임이 DONE 되었을 때 기능 구현
woo-chang Mar 30, 2023
a262462
feat: 게임이 종료되었을 때 게임 상태를 업데이트하는 기능 구현
woo-chang Mar 30, 2023
d55fc6d
feat: 게임 실행 상태 직렬화 및 역직렬화 기능 구현
woo-chang Mar 30, 2023
dc8af3a
refactor: 게임 종료 상태에 따라 다른 메시지를 출력하도록 수정
woo-chang Mar 30, 2023
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ out/

### VS Code ###
.vscode/

### DB ###
src/docker/db
143 changes: 143 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,146 @@
## 우아한테크코스 코드리뷰

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)

## 도메인 객체 그래프

```mermaid
graph TD
ChessController --> InputView
ChessController --> OutputView
ChessController --> ChessGameService
ChessController --> PieceService
ChessController --> ChessGame

ChessGameService --> ChessGameDao
PieceService --> PieceDao

ChessGame --> Board

Square --> File
Square --> Rank

BoardFactory --> Board

Board --> Square
Board --> piece

piece --> Color
piece --> PIECE_TYPE

subgraph PIECE_TYPE
direction BT
Black_Pawn -.-> pieceType
White_Pawn -.-> pieceType
Rook -.-> pieceType
Bishop -.-> pieceType
Knight -.-> pieceType
Queen -.-> pieceType
King -.-> pieceType
end

PIECE_TYPE --> STRATEGY

subgraph STRATEGY
direction BT
DirectStrategy -.-> strategy
SlidingStrategy -.-> strategy
end

STRATEGY --> DirectVector
STRATEGY --> SlidingVector
```

## 구현 기능 목록

### 체스 게임

- [x] 게임을 시작한다.
- [x] 점수를 계산한다.
- [x] 기물을 이동시킨다.
- [x] 게임을 종료한다.
- [x] 게임 승부를 가른다.
- [x] 게임 진행을 확인한다.
- [x] 왕이 죽었는지 확인한다.

### 체스 보드

- [x] 특정 칸의 기물을 확인한다.
- [x] 기물을 이동시킨다.
- [x] 해당 색의 기물 점수를 계산한다.
- [x] 왕이 죽었는지 확인한다.

### 체스 칸

- 세로줄 (File)
- [x] 왼쪽부터 a ~ h이다.
- [x] 파일 간 거리를 계산한다.
- [x] 다음 파일을 반환한다.
- [x] 이전 파일을 반환한다.
- 가로줄 (Rank)
- [x] 아래부터 1 ~ 8이다.
- [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] ID를 통해 체스 게임을 조회한다.
- [x] 가장 최근의 체스 게임을 조회한다.
- [x] 모든 체스 게임을 조회한다.
- [x] 체스 게임 턴을 수정한다.
- [x] 체스 게임을 삭제한다.
- 체스 기물 테이블
- [x] 체스 기물을 저장한다.
- [x] 파일과 랭크를 통해 체스 기물을 조회한다.
- [x] 체스 게임을 통해 모든 체스 기물을 조회한다.
- [x] 체스 기물의 색과 타입을 수정한다.
- [x] 체스 기물을 삭제한다.
- [x] 모든 체스 기물을 삭제한다.
4 changes: 1 addition & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ repositories {
}

dependencies {
implementation 'com.sparkjava:spark-core:2.9.3'
implementation 'com.sparkjava:spark-template-handlebars:2.7.1'
implementation 'ch.qos.logback:logback-classic:1.2.10'
testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
runtimeOnly 'mysql:mysql-connector-java:8.0.28'
}

java {
Expand Down
19 changes: 19 additions & 0 deletions src/docker/data/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CREATE TABLE chess_game
(
`id` INT NOT NULL AUTO_INCREMENT,
`state` VARCHAR(20) NOT NULL,
`turn` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
);

CREATE TABLE piece
(
`id` INT NOT NULL AUTO_INCREMENT,
`chess_game_id` INT NOT NULL,
`color` VARCHAR(20) NOT NULL,
`type` VARCHAR(20) NOT NULL,
`file` VARCHAR(20) NOT NULL,
`rank` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`chess_game_id`) REFERENCES `chess_game` (`id`)
);
18 changes: 18 additions & 0 deletions src/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: "3.9"
services:
db:
image: mysql:8.0.28
platform: linux/x86_64
restart: always
ports:
- "13306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: chess
MYSQL_USER: user
MYSQL_PASSWORD: password
TZ: Asia/Seoul
volumes:
- ./db/mysql/data:/var/lib/mysql
- ./db/mysql/config:/etc/mysql/conf.d
- ./data/init.sql:/docker-entrypoint-initdb.d/init.sql
22 changes: 0 additions & 22 deletions src/main/java/chess/WebApplication.java

This file was deleted.

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

import chess.controller.ChessController;
import chess.dao.ChessGameDao;
import chess.dao.ChessGameDaoImpl;
import chess.dao.PieceDao;
import chess.dao.PieceDaoImpl;
import chess.service.ChessGameService;

public class ChessApplication {

public static void main(String[] args) {
final ChessGameDao chessGameDao = new ChessGameDaoImpl();
final PieceDao pieceDao = new PieceDaoImpl();
final ChessGameService chessGameService = new ChessGameService(chessGameDao, pieceDao);
final ChessController chessController = new ChessController(chessGameService);
chessController.run();
}
}
66 changes: 66 additions & 0 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package chess.controller;

import chess.controller.command.chess.ChessGameCommand;
import chess.controller.command.execute.ExecuteCommand;
import chess.domain.game.ChessGame;
import chess.service.ChessGameService;
import chess.view.InputView;
import chess.view.OutputView;

public class ChessController {

private static final InputView inputView = new InputView();
private static final OutputView outputView = new OutputView();

private final ChessGameService chessGameService;

public ChessController(final ChessGameService chessGameService) {
this.chessGameService = chessGameService;
}

public void run() {
outputView.printStartMessage(chessGameService.loadAllChessGameId());
final ChessGame chessGame = readChessGame();
while (chessGame.isRunning()) {
playChessGame(chessGame);
checkKing(chessGame);
}
printGameOver(chessGame);
}

private ChessGame readChessGame() {
while (true) {
try {
final ChessGameCommand chessGameCommand = inputView.readChessGameCommand();
return chessGameCommand.execute(chessGameService, outputView);
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
}
}
}

private void playChessGame(final ChessGame chessGame) {
try {
final ExecuteCommand executeCommand = inputView.readExecuteCommand();
executeCommand.execute(chessGame, chessGameService, outputView);
} catch (IllegalArgumentException | IllegalStateException e) {
outputView.printErrorMessage(e.getMessage());
}
}

private void checkKing(final ChessGame chessGame) {
if (chessGame.isKingDied()) {
chessGame.done();
chessGameService.updateChessGameStateAndTurn(chessGame);
}
}

private void printGameOver(final ChessGame chessGame) {
if (chessGame.isEnd()) {
outputView.printEndMessage();
}
if (chessGame.isDone()) {
outputView.printDoneMessage();
}
}
}
10 changes: 10 additions & 0 deletions src/main/java/chess/controller/command/chess/ChessGameCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package chess.controller.command.chess;

import chess.domain.game.ChessGame;
import chess.service.ChessGameService;
import chess.view.OutputView;

public interface ChessGameCommand {

ChessGame execute(final ChessGameService chessGameService, final OutputView outputView);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package chess.controller.command.chess;

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

import chess.domain.board.BoardFactory;
import chess.domain.game.ChessGame;
import chess.domain.game.state.EndState;
import chess.domain.game.state.GameState;
import chess.service.ChessGameService;
import chess.view.OutputView;

public class EndChessGameCommand implements ChessGameCommand {

@Override
public ChessGame execute(final ChessGameService chessGameService, final OutputView outputView) {
return new ChessGame(BoardFactory.create(), new GameState(WHITE, EndState.CACHE));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package chess.controller.command.chess;

import chess.domain.game.ChessGame;
import chess.service.ChessGameService;
import chess.view.OutputView;
import chess.view.dto.ChessBoardDto;

public class EnterChessGameCommand implements ChessGameCommand {

private final Long chessGameId;

public EnterChessGameCommand(final String input) {
final String[] commands = input.split(" ");
this.chessGameId = Long.valueOf(commands[1]);
}

@Override
public ChessGame execute(final ChessGameService chessGameService, final OutputView outputView) {
final ChessGame chessGame = chessGameService.loadChessGameById(chessGameId);
outputView.printChessBoard(ChessBoardDto.from(chessGame));
return chessGame;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package chess.controller.command.chess;

import chess.domain.board.BoardFactory;
import chess.domain.game.ChessGame;
import chess.domain.game.state.GameState;
import chess.service.ChessGameService;
import chess.view.OutputView;
import chess.view.dto.ChessBoardDto;

public class NewChessGameCommand implements ChessGameCommand {

@Override
public ChessGame execute(final ChessGameService chessGameService, final OutputView outputView) {
final ChessGame chessGame = savedChessGame(chessGameService);
outputView.printChessBoard(ChessBoardDto.from(chessGame));
return chessGame;
}

private ChessGame savedChessGame(final ChessGameService chessGameService) {
final ChessGame chessGame = new ChessGame(BoardFactory.create(), GameState.START);
chessGameService.saveChessGame(chessGame);
return chessGame;
}
}
Loading