-
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
[3, 4단계 - 체스] 페드로(류형욱) 미션 제출합니다. #730
Changes from 72 commits
b3df817
224a769
16d1110
fd73746
950a8b4
db3cd0f
b88656c
cc0a1cc
f68c2b3
bec3147
b47b964
c962c8a
1b09fd1
725e7f8
41c7bc8
c2419a2
ac5ef1a
c33282b
6a69d5a
dfc1a95
8f06743
c2bd7bc
a39a214
6a2807e
801ae77
9bcc335
8d1c564
c17d59d
33665ae
f471cfb
0b336af
ad1c927
58a5272
a6cfffc
c95705d
b2d1888
13dd3fe
cd69a03
6c50a3a
7a1adf3
3be7b72
107e671
5c98f8b
8b790b2
fb58c54
aa4db24
52c300c
b1f25ff
fb19e82
8800be6
9a9e956
0d7fea2
503576d
e097052
8566ea2
08f66e0
8d13e51
c4e3a1d
fb43fba
fa6eac2
e122c64
5d18908
fbce762
944fb76
f2311d3
86efdba
24b05c8
c7ed770
f6ab2ca
d2001d7
d5b904a
9f390a3
ea4a08f
45fffe5
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 |
---|---|---|
|
@@ -32,4 +32,4 @@ out/ | |
.vscode/ | ||
|
||
### Docker ### | ||
/docker/ | ||
/docker/db |
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 | ||
- ./db/mysql/init:/docker-entrypoint-initdb.d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,35 @@ | ||
package controller; | ||
|
||
import domain.GameCommand; | ||
import domain.game.Board; | ||
import domain.game.BoardInitializer; | ||
import domain.game.Turn; | ||
import domain.game.ChessGame; | ||
import domain.game.GameRequest; | ||
import domain.game.Piece; | ||
import domain.game.TeamColor; | ||
import domain.position.Position; | ||
import service.DBService; | ||
import dto.BoardDto; | ||
import dto.RequestDto; | ||
import java.util.Map; | ||
import java.util.function.Supplier; | ||
import view.InputView; | ||
import view.OutputView; | ||
|
||
public class ChessController { | ||
private final InputView inputView; | ||
private final OutputView outputView; | ||
private final DBService dbService; | ||
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.
제가 질문을 잘 이해를 못한거같은데, db에 저장할 데이터를 컨트롤러단으로 가져오는게 어느부분이죠? 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. // ChessController.java
private void saveCurrentStatus(ChessGame chessGame) {
int gameId = dbService.saveGame(chessGame);
outputView.printSaveResult(gameId);
} 지금은 Service 레이어가 생기면서 사실 현재의 미션에만 국한된 질문은 아니였습니다. 처음 저 의문이 들었던 배경 설명을 좀 드리자면 3단계까지 구현했을 때는 (DB에 저장할 일이 없다 보니) 대표적인 예로 꼭 체스 미션이 아니라 다른 프로젝트들에서도 이렇게 도메인 로직에는 사용되지 않지만 DB 저장을 위해 필요한 게터들이 생기는 경우가 있을 것 같은데, 말씀하신 대로 저장을 위해 당연히 필요한 과정이라고 생각하고 고민 없이 사용하면 되는 부분일까요? 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. 넵 저장에 필요하니 당연히 사용해야죠. 지금 domain과 infra entity가 혼용되어 사용되어 발생하는 의문인데 이걸 나눠서 관리하면 좀 나을거에요. 다만 이것도 중복코드가 많이 발생하기 때문에 트레이드오프가 있어서 프로젝트하실때 직접 경험해보시면 더 좋을거에요. |
||
|
||
public ChessController(final InputView inputView, final OutputView outputView) { | ||
public ChessController(final InputView inputView, final OutputView outputView, final DBService dbService) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
this.dbService = dbService; | ||
} | ||
|
||
public void run() { | ||
outputView.printWelcomeMessage(); | ||
GameCommand command = readUserInput(inputView::inputGameStart); | ||
if (command.isStart()) { | ||
startGame(); | ||
GameRequest gameRequest = readUserInput(inputView::inputGameCommand).asRequest(); | ||
while (gameRequest.isStart() || gameRequest.isLoad()) { | ||
startGame(gameRequest); | ||
outputView.printRestartMessage(); | ||
gameRequest = readUserInput(inputView::inputGameCommand).asRequest(); | ||
} | ||
} | ||
|
||
|
@@ -32,35 +38,84 @@ private <T> T readUserInput(Supplier<T> inputSupplier) { | |
try { | ||
return inputSupplier.get(); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println(e.getMessage()); | ||
outputView.printErrorMessage(e.getMessage()); | ||
} | ||
} | ||
} | ||
|
||
private void startGame() { | ||
Board board = BoardInitializer.init(); | ||
printStatus(board); | ||
private void startGame(GameRequest gameRequest) { | ||
ChessGame chessGame = createGame(gameRequest); | ||
printBoardStatus(chessGame.getPositionsOfPieces()); | ||
|
||
Turn turn = new Turn(); | ||
RequestDto requestDto = readUserInput(inputView::inputGameCommand); | ||
while (requestDto.command().isContinuable()) { | ||
doTurn(board, turn, requestDto); | ||
printStatus(board); | ||
requestDto = readUserInput(inputView::inputGameCommand); | ||
while (shouldProceedGame(gameRequest, chessGame)) { | ||
outputView.printCurrentTurn(chessGame.currentPlayingTeam()); | ||
gameRequest = readUserInput(inputView::inputGameCommand).asRequest(); | ||
processRequest(gameRequest, chessGame); | ||
} | ||
finishGame(gameRequest, chessGame); | ||
} | ||
|
||
private void doTurn(Board board, Turn turn, RequestDto requestDto) { | ||
try { | ||
board.movePiece(turn.current(), requestDto.source(), requestDto.destination()); | ||
turn.next(); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println("[오류] " + e.getMessage()); | ||
private ChessGame createGame(GameRequest gameRequest) { | ||
if (gameRequest.isStart()) { | ||
return new ChessGame(); | ||
} | ||
int gameId = readUserInput(inputView::inputGameId); | ||
return dbService.loadGame(gameId); | ||
} | ||
|
||
private void printStatus(Board board) { | ||
BoardDto boardDto = BoardDto.from(board); | ||
private void printBoardStatus(Map<Position, Piece> positionOfPieces) { | ||
BoardDto boardDto = BoardDto.from(positionOfPieces); | ||
outputView.printBoard(boardDto); | ||
} | ||
|
||
private boolean shouldProceedGame(GameRequest gameRequest, ChessGame chessGame) { | ||
return gameRequest.isContinuable() && !chessGame.isGameEnd(); | ||
} | ||
|
||
private void processRequest(GameRequest gameRequest, ChessGame chessGame) { | ||
if (gameRequest.isSave()) { | ||
saveCurrentStatus(chessGame); | ||
return; | ||
} | ||
if (gameRequest.isContinuable()) { | ||
playRound(gameRequest, chessGame); | ||
} | ||
} | ||
|
||
private void saveCurrentStatus(ChessGame chessGame) { | ||
int gameId = dbService.saveGame(chessGame); | ||
outputView.printSaveResult(gameId); | ||
} | ||
|
||
private void playRound(GameRequest gameRequest, ChessGame chessGame) { | ||
try { | ||
chessGame.move(gameRequest.source(), gameRequest.destination()); | ||
printBoardStatus(chessGame.getPositionsOfPieces()); | ||
} catch (IllegalArgumentException | IllegalStateException e) { | ||
outputView.printErrorMessage(e.getMessage()); | ||
} | ||
} | ||
|
||
private void finishGame(GameRequest gameRequest, ChessGame chessGame) { | ||
outputView.printGameEndMessage(); | ||
if (gameRequest.isEnd()) { | ||
return; | ||
} | ||
|
||
outputView.printStatusInputMessage(); | ||
gameRequest = readUserInput(inputView::inputGameCommand).asRequest(); | ||
if (gameRequest.isStatus()) { | ||
printGameResult(chessGame); | ||
} | ||
} | ||
|
||
private void printGameResult(ChessGame chessGame) { | ||
TeamColor winner = chessGame.getWinner(); | ||
double whiteScore = chessGame.currentScoreOf(TeamColor.WHITE); | ||
double blackScore = chessGame.currentScoreOf(TeamColor.BLACK); | ||
|
||
outputView.printWinner(winner); | ||
outputView.printScore(TeamColor.WHITE, whiteScore); | ||
outputView.printScore(TeamColor.BLACK, blackScore); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package dao; | ||
|
||
import java.sql.Connection; | ||
import java.sql.DriverManager; | ||
import java.sql.SQLException; | ||
|
||
public class DBConnector { | ||
private static final String SERVER = "localhost:13306"; | ||
private static final String DATABASE = "chess"; | ||
private static final String OPTION = "?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; | ||
private static final String USERNAME = "root"; | ||
private static final String PASSWORD = "root"; | ||
|
||
private static DBConnector instance = null; | ||
|
||
private DBConnector() { | ||
} | ||
|
||
public static DBConnector getInstance() { | ||
if (instance == null) { | ||
instance = new DBConnector(); | ||
} | ||
return instance; | ||
} | ||
|
||
public Connection getConnection() { | ||
try { | ||
return DriverManager.getConnection("jdbc:mysql://" + SERVER + "/" + DATABASE + OPTION, USERNAME, PASSWORD); | ||
} catch (final SQLException e) { | ||
throw new DBException("DB 연결 오류", e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package dao; | ||
|
||
public class DBException extends RuntimeException { | ||
private static final String DEFAULT_ERROR_MESSAGE = "쿼리 실행 중 오류가 발생했습니다."; | ||
|
||
public DBException(String message) { | ||
super(message); | ||
} | ||
|
||
public DBException(Throwable cause) { | ||
super(DEFAULT_ERROR_MESSAGE, cause); | ||
} | ||
|
||
public DBException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package dao; | ||
|
||
import domain.game.TeamColor; | ||
import java.sql.Connection; | ||
|
||
public interface GameDao { | ||
int addGame(Connection connection); | ||
|
||
TeamColor findTurn(Connection connection, int gameId); | ||
|
||
void updateTurn(Connection connection, int gameId, TeamColor teamColor); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package dao; | ||
|
||
import domain.game.TeamColor; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.sql.Statement; | ||
|
||
public class GameDaoImpl implements GameDao { | ||
private static final String TABLE_NAME = "game"; | ||
|
||
@Override | ||
public int addGame(Connection connection) { | ||
final String query = String.format("INSERT INTO %s(turn) VALUE(?);", TABLE_NAME); | ||
try (PreparedStatement preparedStatement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) { | ||
preparedStatement.setString(1, TeamColor.WHITE.name()); | ||
preparedStatement.executeUpdate(); | ||
ResultSet resultSet = preparedStatement.getGeneratedKeys(); | ||
if (resultSet.next()) { | ||
return resultSet.getInt(1); | ||
} | ||
} catch (final SQLException e) { | ||
throw new DBException(e); | ||
} | ||
throw new DBException("게임 생성 중 오류가 발생했습니다."); | ||
} | ||
|
||
@Override | ||
public TeamColor findTurn(Connection connection, int gameId) { | ||
final String query = String.format("SELECT turn FROM %s WHERE `gameId` = ?", TABLE_NAME); | ||
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) { | ||
preparedStatement.setInt(1, gameId); | ||
final ResultSet resultSet = preparedStatement.executeQuery(); | ||
if (resultSet.next()) { | ||
String turn = resultSet.getString("turn"); | ||
return TeamColor.valueOf(turn); | ||
} | ||
} catch (SQLException e) { | ||
throw new DBException(e); | ||
} | ||
throw new DBException(gameId + " 에 해당하는 차례를 찾을 수 없습니다."); | ||
} | ||
|
||
@Override | ||
public void updateTurn(Connection connection, int gameId, TeamColor teamColor) { | ||
final var query = String.format("UPDATE %s SET turn = ? WHERE gameId = ?", TABLE_NAME); | ||
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) { | ||
preparedStatement.setString(1, teamColor.name()); | ||
preparedStatement.setInt(2, gameId); | ||
preparedStatement.executeUpdate(); | ||
} catch (SQLException e) { | ||
throw new DBException(e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package dao; | ||
|
||
import dto.PieceDto; | ||
import java.sql.Connection; | ||
import java.util.List; | ||
|
||
public interface PieceDao { | ||
void addAll(Connection connection, List<PieceDto> pieceDtos, int gameId); | ||
|
||
List<PieceDto> findAllPieces(Connection connection, int gameId); | ||
} |
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.
docker compose파일을 잘 올려주시긴했는데 README에 실행법도 간략히 정리되어있으면 더 좋을거같아요
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.
반영했습니다!