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

[4, 5단계 - 체스] 라이언(권영훈) 미션 제출합니다. #235

Merged
merged 130 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
27eea54
docs: 리드미 구현 목록 작성
Mar 16, 2021
7b41611
feat: 프로젝트 파일 구조 생성
Mar 16, 2021
9ff0366
feat(Position): 체스 말의 위치를 나타내는 Position 클래스에서 생성자 구현
Mar 16, 2021
612ce53
feat(Position): 체스 말의 위치가 Grid 범위를 벗어날 경우 예외 출력
Mar 16, 2021
da59418
docs: README 업데이트
Mar 16, 2021
fd15b1a
feat(Piece): 체스말에 대한 추상 클래스 구현
Mar 16, 2021
65371aa
feat(Position): 생성자 추가
Mar 16, 2021
e90c792
feat(Empty): empty예외 구현
Mar 16, 2021
2e65682
feat(King): 킹 스케레톤 코드 구현
Mar 16, 2021
ef48684
refactor: 추상 메서드 삭제 및 파라미터 추가
jaeseongDev Mar 16, 2021
f036d6b
feat(King): move 메서드에 대한 테스트 코드 작성
jaeseongDev Mar 16, 2021
2e26da1
feat(King): 킹 움직임 구현
Mar 16, 2021
2112313
feat(LineTest): Line에 대한 테스트 코드 작성
jaeseongDev Mar 16, 2021
f6b677e
feat(Line): 같은 포지션을 가진 Piece가 있을 경우 예외 발생
Mar 17, 2021
3776fd9
refactor: 움직임 메서드 리펙토링
Mar 17, 2021
96aa010
feat(Grid): 체스판 초기화
Mar 17, 2021
a186116
feat(Direction): 방향 Enum 추가
Mar 17, 2021
f9ecd41
feat(Grid): 그리드 구현
Mar 17, 2021
4dbe3b8
refactor: 메서드 로직 및 구조 리팩터링
Mar 17, 2021
0f5b708
feat(Bishop): 비숍 관련 로직 구현
Mar 17, 2021
3f4f062
feat(Rook): 룩 관련 로직 구현
Mar 17, 2021
6cb36ce
docs: 기능 구현 목록 업데이트
Mar 17, 2021
23e7aef
feat(Queen): 퀸 관련 로직 구현
Mar 17, 2021
16c1962
feat(Knight): 나이트 관련 로직 구현
Mar 17, 2021
c8680f6
refactor(Line): GeneralLine 메서드 로직 수정
Mar 17, 2021
6365cfa
refactor: 불필요한 코드 제거
Mar 17, 2021
75a0b53
fix: 움직일 수 있는 포지션을 구하는 로직 버그 수정
Mar 17, 2021
cdaf2ca
feat(Pawn): 폰에 대한 로직 구현
jaeseongDev Mar 17, 2021
101d677
refactor: Grid 클래스에서 move() 메서드 구현을 위한 재설계
jaeseongDev Mar 17, 2021
1996682
refactor: Grid 클래스에서 static을 지우고 객체를 생성할 수 있도록 만들기
jaeseongDev Mar 18, 2021
bdf163c
refactor: 체스말 배치 네이밍 변경
Mar 18, 2021
b3513ec
refactor: 사용하지 않는 임포트 삭제 및 스타일 수정
Mar 18, 2021
69b30cc
refactor: 가는 방향 검증 네이밍 수정
Mar 18, 2021
9282eef
docs: 폰에 대한 기능 설명 추가
jaeseongDev Mar 18, 2021
206f0b2
Merge branch 'step1' of https://github.com/YounghoonKwon/java-chess i…
jaeseongDev Mar 18, 2021
9875051
feat(Grid): Pawn에 대한 로직 추가
jaeseongDev Mar 18, 2021
5238d71
refactor: Pawn에 대한 처리 로직 리팩토링
jaeseongDev Mar 18, 2021
8324ee8
refactor: 가는 방향 검증 네이밍 수정
Mar 18, 2021
d12ded4
feat(Grid): Pawn에 대한 로직 추가
jaeseongDev Mar 18, 2021
768f509
refactor: Pawn에 대한 처리 로직 리팩토링
jaeseongDev Mar 18, 2021
f776685
Merge branch 'step1' of https://github.com/YounghoonKwon/java-chess i…
jaeseongDev Mar 18, 2021
7097bb3
refactor: domain의 getter들 리팩토링
Mar 18, 2021
c6637dc
feat: 체스판 출력 기능
jaeseongDev Mar 18, 2021
d609d9a
feat: 입력값을 받아 움직이는 기능 추가
jaeseongDev Mar 18, 2021
83e83df
fix: isEmpty 수정
Mar 18, 2021
f1c1002
test: Grid에서 move()가 작동하는 지 테스트 추가
jaeseongDev Mar 18, 2021
7dcd632
feat: 폰 움직임 구현
Mar 18, 2021
e7e0fa5
refactor: controller 분리
Mar 18, 2021
1f8d4c2
docs: 구현한 기능 체크
jaeseongDev Mar 18, 2021
3df65d3
Merge branch 'step1' of https://github.com/YounghoonKwon/java-chess i…
jaeseongDev Mar 18, 2021
d81f786
refactor(ChessController): 컨트롤러 관련 로직 리팩토링
jaeseongDev Mar 18, 2021
0dac739
refactor(Grid): Grid의 move()에 대한 메서드 리팩토링
jaeseongDev Mar 18, 2021
06c9376
refactor: 그리드 역할 분리
jaeseongDev Mar 18, 2021
f80bf5b
refactor: Grid 로직에 대한 메서드 분리
jaeseongDev Mar 18, 2021
36ff8f4
feat: 각 체스 말에 대한 점수 조회 메서드 추가
jaeseongDev Mar 18, 2021
1713ef7
feat: 점수 계산 기능
jaeseongDev Mar 18, 2021
c34bdd3
refactor(Grid): 계산 로직 수정
jaeseongDev Mar 18, 2021
af9fd29
docs: 기능 구현 목록 추가
jaeseongDev Mar 18, 2021
57759a8
refactor: 접근 제어자 및 final 키워드 추가, 메서드 순서 변경
Mar 18, 2021
4bf176c
feat: 플레이어 순서 추가
Mar 18, 2021
1c79923
feat: 승자 판별 구현
Mar 18, 2021
2e380a3
refactor: 자신의 말을 옮길 수 있도록 유효성 검증 코드 리팩토링
jaeseongDev Mar 19, 2021
67f5ce5
refactor: 네이밍 수정(엘레강트 오브젝트 스타일)
Mar 19, 2021
99f8268
refactor: 네이밍 수정(엘레강트 오브젝트 스타일)
Mar 19, 2021
fec2d17
Merge branch 'step1' of https://github.com/YounghoonKwon/java-chess i…
jaeseongDev Mar 19, 2021
7c07e63
refactor(ChessService): 게임 상태를 관리하는 ChessService 클래스 생성해서 책임 분리
jaeseongDev Mar 19, 2021
de7e577
refactor: 입력 받은 명령어마다 클래스를 분리해서 리팩토링
jaeseongDev Mar 19, 2021
15ada50
refactor: 상태 패턴 적용해서 게임 명령어에 따라 다르게 실행할 수 있도록 리팩토링
jaeseongDev Mar 19, 2021
848b55f
refactor: ChessService의 gameOver 속성 제거
jaeseongDev Mar 19, 2021
9b29f8f
refactor: 상태에 관련된 로직의 변수명 수정
jaeseongDev Mar 19, 2021
0537d3f
refactor: 상태 패턴 리팩토링
jaeseongDev Mar 19, 2021
403c3d2
refactor: 불필요한 코드 삭제
jaeseongDev Mar 19, 2021
67e80a6
refactor: 상태패턴 리팩터링
Mar 19, 2021
e35961c
refactor: 매직 넘버 상수로 치환
jaeseongDev Mar 20, 2021
a3826f2
refactor: BlackTurn, WhiteTurn에 대한 로직 수정
jaeseongDev Mar 20, 2021
f078317
Merge branch 'step1' of https://github.com/YounghoonKwon/java-chess i…
jaeseongDev Mar 20, 2021
4d10d37
refactor: Lines로 클래스 분리
jaeseongDev Mar 20, 2021
4ba3daf
refactor: Lines로 클래스 분리
jaeseongDev Mar 20, 2021
963e5b6
refactor: Grid에 불필요한 코드 삭제
jaeseongDev Mar 20, 2021
eece287
refactor: Lines에 대한 접근자 수정
jaeseongDev Mar 20, 2021
f44a710
refactor: grid 역할 분리
Mar 20, 2021
b0f1655
refactor: service 삭제
Mar 20, 2021
dacf443
refactor: 움직이는 로직은 Piece로 이동
jaeseongDev Mar 20, 2021
ac801c1
refactor: 상속과 Override를 막아야하는 클래스 및 메서드에 final 붙이기
Mar 20, 2021
754b9c0
feat: 테스트를 용이하게 하기 위해 Grid에 전략 패턴을 적용
jaeseongDev Mar 20, 2021
b1a602f
test(PwanTest): 폰을 생성하는 클래스에 대한 테스트 추가
jaeseongDev Mar 20, 2021
c43db81
reafactor: try-catch 추가
Mar 20, 2021
a49374d
test(PawnTest): 폰에 대한 로직 테스트 추가
jaeseongDev Mar 20, 2021
f2667a6
feat: 테스트 케이스 추가
Mar 20, 2021
2426a5f
refactor: resolve merge conflict
Mar 20, 2021
d84e0b8
refactor: 테스트 수정
Mar 20, 2021
0ef1dba
test(Empty): Empty에 대한 테스트 로직 추가
jaeseongDev Mar 20, 2021
c055ea6
test(PositionTest): Position에 대한 테스트 추가
jaeseongDev Mar 20, 2021
efd9e9e
test(ScoreTest): Score에 대한 테스트 코드 추가
jaeseongDev Mar 20, 2021
78cbe9d
test: Line, Lines에 대한 테스트 추가
jaeseongDev Mar 20, 2021
a0f156d
test(GridTest): Grid에 대한 테스트 코드 추가
jaeseongDev Mar 20, 2021
ea7de41
fix: 버그 픽스
Mar 20, 2021
1e3b452
refactor: Column, Row Enum 추가 testStrategy 테스트 패키지로 이동
Mar 25, 2021
c31e0fd
refactor: Row, Column Enum으로 랩핑
Mar 25, 2021
d472193
refactor: given, when, then을 기준으로 줄바꿈
Mar 25, 2021
7829565
refactor: 상태패턴 domain으로 이동, controller에서 view 처리하게끔 리팩터링
Mar 25, 2021
ef4f91a
fix: 입력에 따른 에러 수정
Mar 26, 2021
1378d73
Merge branch 'younghoonkwon' of https://github.com/woowacourse/java-c…
Mar 29, 2021
7481be7
docs: 구현 목록 작성 4단계
Mar 29, 2021
b2650d8
feat: html/css 체스보드 작성
Mar 29, 2021
4b9b318
refactor: 컨트롤에서 상태 분리
Mar 30, 2021
719b235
feat: 말 움직임 구현
Mar 30, 2021
e4b061b
feat: 체스판 start 버튼에 따라 브라우저 껏다 켜도 이전 상황 복구
Mar 30, 2021
2bbb124
feat: 점수 계산 및 턴 구현
Mar 31, 2021
46b1733
feat: css 수정
Mar 31, 2021
7c0dbe2
feat: font 변경
Mar 31, 2021
a9ecf49
feat: 버튼 스타일 추가
Mar 31, 2021
61d654e
refactor: King, Queen 심볼 변경
Mar 31, 2021
735ab12
feat: db 구현
Apr 1, 2021
1166ecf
refactor: js 버튼 ui 리팩토링
Apr 1, 2021
bcd5045
refactor: js .then() 함수들 async await으로 리팩토링
Apr 1, 2021
88ef082
refactor: 스타일 변경
Apr 1, 2021
d01058e
refactor: css 패키지 분리
Apr 1, 2021
7fa3488
refactor: turn 싱크 안맞는 부분 수정
Apr 1, 2021
fb50826
refactor: 쓰이지 않는 코드 리팩토링
Apr 1, 2021
74c4fd9
refactor: PieceMapper 추가
Apr 2, 2021
430598d
refactor: Enum PieceMapper 리팩토링
Apr 2, 2021
f26dc31
refactor: response 처리 필요없는거 삭제
Apr 2, 2021
9837de7
docs: 구현 목록 업데이트
Apr 2, 2021
6523c82
refactor: 커맨트 삭제
Apr 3, 2021
5849615
refactor: Chess 엔티티 패키지 분리
Apr 9, 2021
ad8d890
feat: connection test 추가
Apr 9, 2021
5c32d38
refactor: html response message 수정
Apr 9, 2021
56d3516
feat: connection pooling 구현
Apr 9, 2021
6efff11
refactor: 주석 삭제
Apr 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,15 @@
- [x] 왕 잡으면 종료되는 기능
- [x] Status: (말이 잡힐때마다 업데이트)
- [x] 승패여부 및 점수 관리(3단계 이후)
- [x] 플레이어가 자신의 말만 옮길 수 있는 유효성 검증 넣기
- [x] 플레이어가 자신의 말만 옮길 수 있는 유효성 검증 넣기


## 4단계
- [x] ChessBoard에 대한 html파일을 만든다.
- [x] ChessBoard에 대한 css파일을 만든다.
- [x] ChessBoard에서 클릭하는 부분 자바스크립트 작성.
- [x] ChessBoard에서 클릭한 정보 백엔드로 전송
- [x] 백엔드에서 rest api 작성

## 5단계
- [x] 진행중이던 게임을 불러오는 Db 구현.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ dependencies {
compile('ch.qos.logback:logback-classic:1.2.3')
testCompile('org.junit.jupiter:junit-jupiter:5.6.0')
testCompile('org.assertj:assertj-core:3.15.0')
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'

Choose a reason for hiding this comment

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

이건 개인적인 궁금함인데요. Jackson이 아닌 Gson 라이브러리를 사용한 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

Spring 에서는 Jackson을 기본으로 내장 하는 것으로 알고있는데 spark는 따로 언급 없이 spark documentation에 Gson으로 사용하길래, 따라했어요!

조금 찾아봤는데,
대용량 파일에서는 Jackson이 GSON보다 2배가량 빠르고,
작은 파일에서는 GSON이 Jackson보다 아주 약간? 빠르네요.

하지만, GSON은 maintenance가 더이상 안되는 것으로 보이며, moshi라는 것으로 대체되는 추세인것 같습니다.

google/gson#1821
https://www.overops.com/blog/the-ultimate-json-library-json-simple-vs-gson-vs-jackson-vs-json/

Choose a reason for hiding this comment

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

추가 학습까지 하시고 이렇게 공유까지 해주시다니 정말 멋지네요 👍

이런 피드백을 드린 이유는 어떤 기준을 가지고 라이브러리를 선택했는지가 궁금했어요!
그리고 저는 설령 그 기준이 틀렸다하더라도 그런 고민하는 시간이 의미있다고 생각하거든요. ^^

implementation("mysql:mysql-connector-java:8.0.16")
implementation group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4'

}

test {
Expand Down
86 changes: 83 additions & 3 deletions src/main/java/chess/WebUIChessApplication.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,98 @@
package chess;

import chess.dao.ChessDAO;
import chess.domain.grid.ChessGame;
import chess.domain.grid.Grid;
import chess.domain.grid.gridStrategy.NormalGridStrategy;
import chess.domain.piece.Color;
import chess.domain.position.Position;
import chess.dto.PositionDTO;
import chess.entity.Chess;
import com.google.gson.Gson;
import spark.ModelAndView;
import spark.template.handlebars.HandlebarsTemplateEngine;

import java.sql.SQLDataException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static spark.Spark.get;
import static spark.Spark.*;

public class WebUIChessApplication {
private static final Gson GSON = new Gson();
private static final int SUCCESSFUL_RESPONSE = 200;
private static final int CLIENT_ERROR_RESPONSE = 400;
private static final String CHESS_ID = "1";

public static void main(String[] args) {
staticFiles.location("/public");
ChessGame chessGame = new ChessGame(new Grid(new NormalGridStrategy()));
ChessDAO chessDAO = new ChessDAO();

get("/", (req, res) -> {
Map<String, Object> model = new HashMap<>();
return render(model, "index.html");
return render(new HashMap<>(), "index.html");
});

get("/pieces", (req, res) -> {
return chessGame.pieceMap();
}, GSON::toJson);

get("/turn", (req, res) -> {
return chessGame.turn();
}, GSON::toJson);

get("/score/white", (req, res) -> {
return chessGame.score(Color.WHITE);
}, GSON::toJson);

get("/score/black", (req, res) -> {
return chessGame.score(Color.BLACK);
}, GSON::toJson);

get("/gameover", (req, res) -> {
return Arrays.asList(chessGame.isGameOver(), chessGame.getWinner());
}, GSON::toJson);

post("/move", (req, res) -> {
PositionDTO positionDTO = GSON.fromJson(req.body(), PositionDTO.class);
String sourcePosition = positionDTO.getSourcePosition();
String targetPosition = positionDTO.getTargetPosition();
try {
chessGame.move(chessGame.grid().piece(new Position(sourcePosition)),
chessGame.grid().piece(new Position(targetPosition)));
return SUCCESSFUL_RESPONSE;

Choose a reason for hiding this comment

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

클라이언트 입장에서 HTTP 상태 코드 200과 별개로, 응답 값으로 200이 내려오면 이게 숫자 200을 의미하는지 상태를 의미하는지 헷갈릴 수도 있지 않을까?란 피드백이었어요. ^^

} catch (IllegalArgumentException error) {
return CLIENT_ERROR_RESPONSE;
}
});

post("/start", (req, res) -> {
chessGame.start();
return SUCCESSFUL_RESPONSE;
});

post("/reset", (req, res) -> {
chessGame.reset();
return SUCCESSFUL_RESPONSE;
});

post("/save", (req, res) -> {
Chess chess = new Chess(CHESS_ID, chessGame.gridStringify(), chessGame.turn().name());
if (chessDAO.findByChessId(CHESS_ID) == null) {
chessDAO.addChess(chess);
}
chessDAO.updateChess(chess, chess.getChess(), chess.getTurn());
return SUCCESSFUL_RESPONSE;
});

post("/load", (req, res) -> {
if (chessDAO.findByChessId(CHESS_ID) == null) {
throw new SQLDataException("저장된 보드가 없습니다.");
}
Chess chess = chessDAO.findByChessId(CHESS_ID);
chessGame.load(chess);
return SUCCESSFUL_RESPONSE;
});
}

Expand Down
84 changes: 36 additions & 48 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -1,86 +1,78 @@
package chess.controller;

import chess.domain.grid.ChessGame;
import chess.domain.grid.Grid;
import chess.domain.grid.gridStrategy.GridStrategy;
import chess.domain.grid.gridStrategy.NormalGridStrategy;
import chess.domain.piece.Color;
import chess.domain.state.*;
import chess.domain.piece.Piece;
import chess.domain.position.Position;
import chess.view.InputView;
import chess.view.OutputView;

import java.util.Arrays;
import java.util.List;

public class ChessController {
private static final String COMMAND_START = "start";
private static final String COMMAND_END = "end";
private static final String COMMAND_MOVE = "move";
private static final String COMMAND_STATUS = "status";

private GameState gameState;

public ChessController() {
this.gameState = new Ready();
}
private static final String WHITE_SPACE_DELIMITER = " ";

public final void run() {
OutputView.printChessInstruction();
GridStrategy gridStrategy = new NormalGridStrategy();
Grid grid = new Grid(gridStrategy);
ChessGame game = new ChessGame(grid);
do {
command(grid);
command(game);
}
while (!gameState.isFinished());
while (!game.isFinished());
}

private void command(final Grid grid) {
private void command(final ChessGame game) {
try {
runCommand(grid);
runCommand(game);
} catch (IllegalArgumentException error) {
OutputView.printError(error);
}
}

private void runCommand(final Grid grid) {
private void runCommand(final ChessGame game) {
String command = InputView.command();
if (command.equals(COMMAND_START)) {
startCommand(grid, command);
startCommand(game);
return;
}
if (command.equals(COMMAND_END)) {
endCommand();
endCommand(game);
return;
}
if (command.equals(COMMAND_STATUS)) {
statusCommand(grid);
statusCommand(game);
return;
}
if (command.startsWith(COMMAND_MOVE)) {
moveCommand(grid, command);
moveCommand(game, command);
return;
}
throw new IllegalArgumentException("잘못 입력 하셨습니다.");
}

private void startCommand(final Grid grid, final String command) {
if (gameState instanceof Ready) {
OutputView.printGridStatus(grid.lines());
gameState = gameState.run(grid, command);
return;
}
throw new IllegalArgumentException("게임이 이미 시작 하였습니다.");
private void startCommand(final ChessGame game) {
OutputView.printGridStatus(game.grid().lines());
game.start();
}

private void endCommand() {
gameState = new End();
private void endCommand(ChessGame game) {
game.end();
}

private void statusCommand(final Grid grid) {
if (gameState instanceof Ready) {
throw new IllegalArgumentException("게임을 아직 시작 하지 않았습니다.");
}
if (gameState instanceof Playing) {
gameState = new Status();
}
double blackScore = grid.score(Color.BLACK);
double whiteScore = grid.score(Color.WHITE);
private void statusCommand(final ChessGame game) {
game.status();
double blackScore = game.grid().score(Color.BLACK);
double whiteScore = game.grid().score(Color.WHITE);
OutputView.printScores(Color.BLACK, blackScore);
OutputView.printScores(Color.WHITE, whiteScore);
if (blackScore > whiteScore) {
Expand All @@ -91,21 +83,17 @@ private void statusCommand(final Grid grid) {
}
}

private void moveCommand(final Grid grid, final String command) {
if (!(gameState instanceof Playing)) {
throw new IllegalArgumentException("게임을 아직 시작 하지 않았습니다.");
}
gameState = gameState.run(grid, command);
if (!grid.kingSurvived(Color.BLACK)) {
OutputView.printWinner(Color.WHITE);
gameState = new End();
return;
}
if (!grid.kingSurvived(Color.WHITE)) {
OutputView.printWinner(Color.BLACK);
gameState = new End();
private void moveCommand(final ChessGame game, final String command) {
List<String> moveInput = Arrays.asList(command.split(WHITE_SPACE_DELIMITER));
Position sourcePosition = new Position(moveInput.get(1));
Position targetPosition = new Position(moveInput.get(2));
Piece sourcePiece = game.grid().piece(sourcePosition);
Piece targetPiece = game.grid().piece(targetPosition);
game.move(sourcePiece, targetPiece);
if (game.isGameOver()) {
OutputView.printWinner(game.getWinner());
return;
}
OutputView.printGridStatus(grid.lines());
OutputView.printGridStatus(game.grid().lines());
}
}