Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7d27a33
fix: 향상된 문법으로 equals 수정
junseoplee Jul 19, 2024
d6ca9b5
docs: 기능 요구 사항 업데이트
junseoplee Jul 20, 2024
5e9f872
feat: 승리한 팀을 찾고 출력하는 기능 구현
junseoplee Jul 20, 2024
fba2d73
feat: King 이 잡혔을 때 승리 팀과 점수를 출력하는 기능 구현
junseoplee Jul 22, 2024
90f634b
fix: Pawn 피스가 적이 없을 경우에도 대각선으로 움직일 수 있던 오류 수정
junseoplee Jul 22, 2024
89edcb7
docs: 기능 요구 사항 정리
junseoplee Jul 22, 2024
0218cec
refactor: 프로젝트 구조 수정
junseoplee Jul 23, 2024
c786f3d
feat: 게임별로 구분할 수 있는 ChessGame 클래스 구현, 저장할 수 있도록 상태를 나타내는 State 열거형 구현
junseoplee Jul 23, 2024
5fd16d9
feat: DB 연결에 필요한 설정 추가
junseoplee Jul 23, 2024
54b66b5
feat: DB 연결을 위한 ChessGameDao 기능 추가
junseoplee Jul 23, 2024
9f7f78c
feat: DB 연결을 위한 PieceDao 기능 추가
junseoplee Jul 23, 2024
037471d
feat: DB 연결을 위한 PieceDao 기능 추가
junseoplee Jul 23, 2024
61d451a
fix: DB 연결을 위한 설정 수정
junseoplee Jul 25, 2024
3f07391
refactor: Board 반환을 위한 리팩토링
junseoplee Jul 25, 2024
a4d293e
refactor: 진행 상태를 보다 명확하게 알 수 있도록 변경
junseoplee Jul 25, 2024
e20a260
feat: DB 연결 기능과 컨트롤러 조립
junseoplee Jul 25, 2024
80b7e47
docs: 기능 요구 사항 및 에러메세지 업데이트
junseoplee Jul 25, 2024
a3ac67f
fix: 기존 게임이 정상적으로 불러와지지 않던 오류 수정
junseoplee Jul 25, 2024
ddfb961
refactor: 명령어를 다루는 책임을 컨트롤러에서 분리
junseoplee Jul 29, 2024
7c6c78e
feat: UnsupportedOperationException 으로 사용되지 않는 메서드 관리
junseoplee Jul 29, 2024
0ad0e65
test: 폰의 공격 움직임을 검증하는 테스트 추가
junseoplee Jul 29, 2024
3ce712d
fix: 변수 이름을 명확하게 수정
junseoplee Jul 29, 2024
d5483e4
fix: 상태를 더 명확하게 나타낼 수 있는 이름으로 수정
junseoplee Jul 29, 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
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,52 @@
- [x] 체스 말이 반환한 경로 안에 다른 체스 말이 있는지 검사
- [x] 경로 안에 다른 체스 말이 있다면 이동할 수 없다 <- Path
- **입력**
- [x] move source위치 target위치을 실행해 이동한다
- [x] move source 위치 target 위치을 실행해 이동한다

## 3단계 - 승패 및 점수
### 기능 요구 사항
- [x] King이 잡혔을 때 게임을 종료해야 한다
- [x] King 이 잡혔을 때 게임을 종료해야 한다
- [x] 체스판에서 잡힌 말을 반환
- [x] 체스 말에서 해당 말의 타입을 반환
- [x] status 명령어를 입력하면 점수를 출력
- [x] 점수를 계산하는 ScoreCalculator 클래스
- [x] 같은 File 에 있는 Pawn 은 0.5점을 준다

## 4단계 - DB 적용
### 기능 요구 사항
- **DB 연결 전 기능**
- [x] end 명령어를 입력하면 각자의 점수와 승리 팀을 출력한다
- [x] 점수를 계산해서 점수가 높은 팀이 승리한다
- **DB 연결**
- [x] 애플리케이션을 재시작하더라도 이전에 하던 체스 게임을 다시 시작할 수 있어야 한다
- [x] 이어하기
- 이전에 진행하던 게임이 있다면 이어서 게임을 시작한다
- 이전에 진행하던 게임이 없다면 새로운 게임을 시작한다
- [x] 새로하기
- 이전에 진행하던 게임이 있어도 새로운 게임을 시작한다

- chessGame 을 따로 저장, Turn 을 저장할 필요가 있음, 게임의 진행 상태를 저장할 필요가 있음

- [x] 피스를 이동할 때 마다 피스 테이블을 업데이트한다
- [x] 체스 게임을 저장할 수 있다
- [x] 체스 게임을 찾을 수 있다
- [x] 체스 게임을 삭제할 수 있다

```
CREATE TABLE chess_game (
id BIGINT NOT NULL AUTO_INCREMENT,
Copy link
Owner

Choose a reason for hiding this comment

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

  1. auto_increment가 무엇인가요?
  2. id를 auto_increment로 설정한 이유는 무엇인가요?

Copy link
Author

Choose a reason for hiding this comment

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

  1. AUTO_INCREMENT는 DB에서 특정 칼럼의 값을 자동으로 증가시킵니다.
  2. 프라이머리 키는 각 행들의 데이터 식별을 위해 고유한 값을 가져야하기 때문에 서로 다른 값을 갖게 하기 위해 AUTO_INCREMENT로 설정했습니다.
    다른 테이블에서 포링 키로 참조할 수 있도록하고, 데이터의 중복이 없는 무결성을 보장할 수 있습니다.

turn VARCHAR(16) NOT NULL,
PRIMARY KEY (id)
);

CREATE TABLE piece (
id BIGINT NOT NULL AUTO_INCREMENT,
chess_game_id BIGINT NOT NULL,
piece_file INT NOT NULL,
piece_rank INT NOT NULL,
color VARCHAR(16),
type VARCHAR(16),
PRIMARY KEY (id)
);

```
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ repositories {
dependencies {
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
18 changes: 10 additions & 8 deletions src/main/java/chess/ChessApplication.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package chess;

import chess.controller.ChessController;
import chess.model.command.CommandFactory;
import chess.model.board.InitialBoard;
import chess.dao.chessGame.JdbcChessGameDao;
import chess.dao.piece.JdbcPieceDao;
import chess.service.ChessGameService;
import chess.view.InputView;
import chess.view.OutputView;
import java.sql.SQLException;

public class ChessApplication {

public static void main(String[] args) {
public static void main(String[] args) throws SQLException {

final JdbcChessGameDao chessGameDao = new JdbcChessGameDao();
final JdbcPieceDao PieceDao = new JdbcPieceDao();
final ChessGameService chessGameService = new ChessGameService(chessGameDao, PieceDao);
InputView inputView = new InputView();
OutputView outputView = new OutputView();
CommandFactory commandFactory = new CommandFactory();
InitialBoard initialBoard = new InitialBoard();
final ChessController chessController = new ChessController(chessGameService, inputView, outputView);

ChessController chessController = new ChessController(inputView, outputView, commandFactory,
initialBoard);
chessController.runChess();
chessController.run();
}
}
196 changes: 132 additions & 64 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -1,90 +1,158 @@
package chess.controller;

import chess.model.command.CommandFactory;
import chess.model.command.CommandLauncher;
import chess.model.ErrorMessage;
import chess.model.board.Board;
import chess.model.board.InitialBoard;
import chess.model.piece.Piece;
import chess.model.piece.PieceInfo;
import chess.model.position.Color;
import chess.model.position.Position;
import chess.model.score.ScoreCalculator;
import chess.controller.command.Command;
import chess.controller.command.InitialCommand;
import chess.domain.game.ChessGame;
import chess.domain.game.State;
import chess.domain.position.Color;
import chess.domain.position.Position;
import chess.service.ChessGameService;
import chess.view.InputView;
import chess.view.OutputView;
import java.sql.SQLException;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

public class ChessController {
Copy link
Owner

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.

깔쌈하게 리팩토링했습니다.


private static final int COMMAND_INDEX = 0;
private static final int SOURCE_POSITION_INDEX = 1;
private static final int TARGET_POSITION_INDEX = 2;

private final Map<Command, BiConsumer<ChessGame, List<String>>> commands =
new EnumMap<>(Command.class);
private final ChessGameService chessGameService;

private final InputView inputView;
private final OutputView outputView;
private final CommandFactory commandFactory;
private final Board board;
private Color currentTurn;
private boolean isRunning;

public ChessController(InputView inputView, OutputView outputView, CommandFactory commandFactory, InitialBoard initialBoard) {
public ChessController(ChessGameService chessGameService, InputView inputView,
OutputView outputView) {
putCommands();
this.chessGameService = chessGameService;
this.inputView = inputView;
this.outputView = outputView;
this.commandFactory = commandFactory;
this.board = initialBoard.createInitialBoard();
this.currentTurn = Color.WHITE;
this.isRunning = true;
}

public void runChess() {
outputView.printStartMessage();
CommandLauncher receivedCommand = null;

while (receivedCommand == null) {
try {
String initialCommandInput = inputView.receiveCommand();
receivedCommand = commandFactory.createCommand(initialCommandInput);
if (receivedCommand.validateInitialCommandType()) {
break;
}
System.out.println(ErrorMessage.INVALID_INITIAL_COMMAND.getMessage());
receivedCommand = null;
} catch (IllegalArgumentException exception) {
System.out.println(exception.getMessage());
}
}

private void putCommands() {
commands.put(Command.START, (chessGame, ignored) -> start(chessGame));
commands.put(Command.END, (chessGame, ignored) -> end(chessGame));
commands.put(Command.STATUS, (chessGame, ignored) -> status(chessGame));
commands.put(Command.MOVE, this::movePiece);
}

private void start(ChessGame chessGame) {
chessGame.start();
outputView.printBoard(chessGame.getBoard().getMap());
}

private void end(ChessGame chessGame) {
chessGame.end();
}

private void status(ChessGame chessGame) {
final Double whiteScore = chessGame.calculateScore(Color.WHITE);
final Double blackScore = chessGame.calculateScore(Color.BLACK);
printScoreAndWinningColor(whiteScore, blackScore);
}

private void movePiece(ChessGame chessGame, List<String> commandParts) {
final Position source = parsePosition(commandParts.get(SOURCE_POSITION_INDEX));
final Position target = parsePosition(commandParts.get(TARGET_POSITION_INDEX));
chessGame.movePiece(source, target);
chessGameService.updatePiece(chessGame, source, target);
outputView.printBoard(chessGame.getBoard().getMap());
}

public void run() throws SQLException {
ChessGame chessGame = initializeChessGame(receiveInitialCommand());

while (isRunnable(chessGame)) {
executeCommand(chessGame);
}
processIfKingCaptured(chessGame);
}

receivedCommand.execute(this);

while (isRunning) {
try {
String commandInput = inputView.receiveCommand();
receivedCommand = commandFactory.createCommand(commandInput);
if (receivedCommand.validateStatusCommandType()) {
calculateAndPrintCurrentTurnScore();
} else {
receivedCommand.execute(this);
currentTurn = currentTurn.changeTurn(currentTurn);
}
} catch (IllegalArgumentException exception) {
System.out.println(exception.getMessage());
}
private boolean isRunnable(ChessGame chessGame) {
return chessGame.getState().equals(State.RUNNING)
|| chessGame.getState().equals(State.WAITING);
}

private void processIfKingCaptured(final ChessGame chessGame) {
if (chessGame.getState().equals(State.CHECKMATE)) {
final Color winner = chessGame.getTurn();
outputView.printWinningColor(winner);
}
}

private void executeCommand(ChessGame chessGame) {
try {
outputView.printCommandMessage();
final List<String> commandParts = List.of(inputView.receiveCommand().split(" "));
final Command command = Command.findCommand(commandParts.get(COMMAND_INDEX));
commands.get(command).accept(chessGame, commandParts);
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
executeCommand(chessGame);
}
}

public void startGame() {
outputView.printBoard(board.getMap());
private InitialCommand receiveInitialCommand() {
try {
outputView.printInitialMessage();
final String command = inputView.receiveCommand();
return InitialCommand.findCommand(command);
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
return receiveInitialCommand();
}
}

public void endGame() {
isRunning = false;
private ChessGame initializeChessGame(InitialCommand command) throws SQLException {
ChessGame chessGame = findChessGameIfContinue(command);
// new 입력하면 메서드가 작동하지 않아 null 로 반환된다
if (chessGame == null) {
outputView.printNewGameMessage();
chessGameService.deleteChessGame();
chessGame = chessGameService.initializeChessGame();
}
return chessGame;
}

public void movePiece(Position source, Position target) {
Piece capturedPiece = board.move(source, target, currentTurn);
if (capturedPiece != null && capturedPiece.pieceType() == PieceInfo.KING) {
endGame();
private ChessGame findChessGameIfContinue(final InitialCommand command) throws SQLException {
ChessGame chessGame = null;
if (command.equals(InitialCommand.CONTINUE)) {
chessGame = chessGameService.findChessGame();
printContinueMessage(chessGame);
}
return chessGame;
}

private void printContinueMessage(final ChessGame chessGame) {
if (chessGame == null) {
outputView.printNoExistsRunningGameMessage();
}
outputView.printContinueMessage();
}

private void printScoreAndWinningColor(Double whiteScore, Double blackScore) {
outputView.printScore(whiteScore, blackScore);
if (whiteScore > blackScore) {
outputView.printWinningColor(Color.WHITE);
}
if (whiteScore < blackScore) {
outputView.printWinningColor(Color.BLACK);
}
if (whiteScore.equals(blackScore)) {
outputView.printDraw();
}
outputView.printBoard(board.getMap());
}

public void calculateAndPrintCurrentTurnScore() {
double score = ScoreCalculator.calculate(board.getMap(), currentTurn);
outputView.printCurrentTurnScore(currentTurn, score);
private static Position parsePosition(String position) {
int file = position.charAt(0) - 'a' + 1;
int rank = position.charAt(1) - '0';
return new Position(file, rank); // 생성자에 1~8 유효성 검사가 있다
}
}
24 changes: 24 additions & 0 deletions src/main/java/chess/controller/command/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package chess.controller.command;

import chess.domain.ErrorMessage;
import java.util.Arrays;

public enum Command {
START("start"),
END("end"),
STATUS("status"),
MOVE("move");

private final String command;

Command(final String command) {
this.command = command;
}

public static Command findCommand(final String value) {
return Arrays.stream(values())
.filter(command -> command.command.equals(value))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.INVALID_COMMAND.getMessage()));
}
}
22 changes: 22 additions & 0 deletions src/main/java/chess/controller/command/InitialCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package chess.controller.command;

import chess.domain.ErrorMessage;
import java.util.Arrays;

public enum InitialCommand {
NEW("new"),
CONTINUE("continue");

private final String command;

InitialCommand(String command) {
this.command = command;
}

public static InitialCommand findCommand(final String value) {
return Arrays.stream(values())
.filter(command -> command.command.equals(value))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.INVALID_INITIAL_COMMAND.getMessage()));
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package chess.model.command;

import chess.model.command.commands.EndCommand;
import chess.model.command.commands.MoveCommand;
import chess.model.command.commands.StartCommand;
import chess.model.ErrorMessage;
import chess.model.command.commands.StatusCommand;
import chess.model.position.Position;
package chess.controller.command.commands;

import chess.domain.ErrorMessage;
import chess.domain.position.Position;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package chess.model.command;
package chess.controller.command.commands;

import chess.controller.ChessController;

Expand Down
Loading