-
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단계 - 체스] 몰리(김지민) 미션 제출합니다. #791
Changes from 116 commits
24a97a3
401b894
2fb03b5
fae3909
c8b8d42
ae20320
ed77e6c
a11ca19
51ed08a
bdb1ef0
33700c3
268ac49
a5185cd
dc13a62
4183c3d
96a6038
ce8a6a3
be855f4
329b27a
f6db0b8
9bcfd67
dd21d25
5cd033a
8b7073b
16ce484
be7de57
d9477a4
aad13c2
df9bd37
a1df2a4
c4c9309
bb5bc05
71541df
16daf5b
9cd97e5
a22bf90
9763153
be5957b
5147bed
64d8039
9e89a49
ebd9b84
860d072
6bc0880
28869f3
4f759c7
c1b5f4a
d77e89a
603a772
9dc16f9
afac83e
f225430
36b1541
b6f4a58
4fd6574
b364412
6c61b9a
1f91692
5a0dbc6
041202b
4e426bb
e2a39ba
9fc8bee
4672b09
38c9b93
4470230
b2a038f
155a92e
f7c678c
2b00dc3
d7412f5
39184ca
f389cbd
2218494
b885bf1
8a7699f
235792c
3c0cc21
86ba136
a6c6b9a
611a76d
3f858ee
cf27f9b
e45545f
a2129d5
51b1699
de49715
16a8e8a
b0c8f1a
3e5aec1
ee89cd4
498bfa5
b409982
a3f41aa
dcb595e
f9ac2f8
7345e75
2404075
3070131
89f6380
51d06e1
0c46af2
fd45dee
aec228f
19d56a1
6dec859
ca7ebd7
30e78e4
fd3f758
d2979f0
a415567
a2e7ba9
ae7bb18
513120b
3276d42
0522e16
3a44feb
eea10af
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 |
---|---|---|
@@ -0,0 +1,21 @@ | ||
DROP DATABASE IF EXISTS chess; | ||
CREATE DATABASE chess DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; | ||
GRANT ALL PRIVILEGES ON `chess`.* TO 'user'@'%'; | ||
FLUSH PRIVILEGES; | ||
SHOW TABLES in chess; | ||
USE chess; | ||
|
||
CREATE TABLE Turn | ||
( | ||
turn_id INT AUTO_INCREMENT PRIMARY KEY, | ||
turn VARCHAR(255) NOT NULL | ||
); | ||
|
||
CREATE TABLE Piece | ||
( | ||
piece_id INT AUTO_INCREMENT PRIMARY KEY, | ||
color VARCHAR(255) NOT NULL, | ||
pieceType VARCHAR(255) NOT NULL, | ||
`rank` INT NOT NULL, | ||
file INT NOT NULL | ||
); | ||
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 | ||
jminkkk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- ./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,61 +1,127 @@ | ||
package chess.controller; | ||
|
||
import chess.domain.board.Board; | ||
import chess.domain.board.BoardInitializer; | ||
import chess.domain.board.ClearBoardInitializer; | ||
import chess.domain.board.SavedBoardInitializer; | ||
import chess.domain.game.Game; | ||
import chess.domain.piece.Color; | ||
import chess.domain.piece.Piece; | ||
import chess.domain.position.Position; | ||
import chess.domain.scorerule.Referee; | ||
import chess.service.ChessGameService; | ||
import chess.view.GameCommand; | ||
import chess.view.InputView; | ||
import chess.view.OutputView; | ||
import java.util.Map; | ||
|
||
public class ChessGameController { | ||
|
||
private final OutputView outputView; | ||
private final InputView inputView; | ||
private final ChessGameService gameService; | ||
Comment on lines
16
to
+20
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. service 라는 명칭을 사용한 이유가 있나요? 🤔 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. 스프링을 사용할 때, 컨트롤러와 레포지토리 사이에서 비즈니스 로직을 처리하는 Service 계층을 사용했었는데요..! 제가 생각하기에 Service 계층의 역할은 크게 2가지라고 생각합니다!
이번 미션에서 비즈니스 로직은 도메인에서 거의 처리가 되었기 때문에, 1번 역할을 수행하지는 않았는데요. 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 계층)가 수행할 수 있는 걸로 보여요. 결국 service 계층은 2번처럼 비즈니스 로직과 영속 계층사이 소통만 담당하는 것이 이상적이겠네요! 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. 넵넵 그동안 service 계층에 대한 오해가 조금 있었던 것 같네요 🤣 감사합니다 현구막! |
||
|
||
public ChessGameController(final InputView inputView, final OutputView outputView) { | ||
public ChessGameController(final InputView inputView, final OutputView outputView, | ||
final ChessGameService gameService) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
this.gameService = gameService; | ||
} | ||
|
||
public void start() { | ||
outputView.printInitialMessage(); | ||
GameCommand gameCommand = inputView.getGameCommand(); | ||
checkStart(gameCommand); | ||
checkStart(inputView.getGameCommand()); | ||
|
||
if (gameService.existSavedGame() && inputView.isPlaySavedGame()) { | ||
playSavedGame(); | ||
return; | ||
} | ||
|
||
play(); | ||
playNewGame(); | ||
} | ||
|
||
private void checkStart(final GameCommand gameCommand) { | ||
if (gameCommand != GameCommand.START) { | ||
if (gameCommand.isNotStartCommand()) { | ||
throw new IllegalArgumentException("시작 명령어를 입력해주세요."); | ||
} | ||
} | ||
|
||
private void play() { | ||
Board board = initializeBoard(); | ||
private void playSavedGame() { | ||
Color turnColor = gameService.findTurn() | ||
.orElseThrow(() -> new IllegalStateException("저장된 게임이 정상적이지 않습니다. 다시 실행해주세요.")); | ||
Game game = Game.of(new SavedBoardInitializer(gameService.findAllPiece()), turnColor); | ||
outputView.printBoard(game.getBoard()); | ||
outputView.printCurrentTurn(game.getTurn()); | ||
execute(game); | ||
} | ||
|
||
private void playNewGame() { | ||
Game game = new Game(new ClearBoardInitializer()); | ||
outputView.printBoard(game.getBoard()); | ||
execute(game); | ||
} | ||
|
||
private void execute(final Game game) { | ||
GameCommand gameCommand = inputView.getGameCommand(); | ||
|
||
while (gameCommand == GameCommand.MOVE) { | ||
playTurn(board); | ||
while (isGameActionIfOngoing(game, gameCommand)) { | ||
executeMoveCommand(game, gameCommand); | ||
executeStatusCommand(game, gameCommand); | ||
gameCommand = inputView.getGameCommand(); | ||
} | ||
|
||
if (gameCommand == GameCommand.START) { | ||
play(); | ||
checkGameRestart(gameCommand); | ||
checkGameFinish(game); | ||
checkGameTerminate(game, gameCommand); | ||
} | ||
|
||
private boolean isGameActionIfOngoing(final Game game, final GameCommand gameCommand) { | ||
return !game.isFinish() && gameCommand.isOnGoingGameCommand(); | ||
} | ||
|
||
private void executeMoveCommand(final Game game, final GameCommand gameCommand) { | ||
if (gameCommand.isMoveCommand()) { | ||
executeTurn(game); | ||
} | ||
} | ||
|
||
private void executeStatusCommand(final Game game, final GameCommand gameCommand) { | ||
if (gameCommand.isViewStatusCommand()) { | ||
viewScore(game.getBoard()); | ||
} | ||
} | ||
|
||
private void checkGameRestart(final GameCommand gameCommand) { | ||
if (gameCommand.isStartGameCommand()) { | ||
playNewGame(); | ||
} | ||
} | ||
|
||
private void checkGameFinish(final Game game) { | ||
if (game.isFinish()) { | ||
outputView.printFinish(); | ||
gameService.delete(); | ||
} | ||
} | ||
|
||
private Board initializeBoard() { | ||
Board board = new Board(new BoardInitializer()); | ||
outputView.printBoard(board); | ||
return board; | ||
private void checkGameTerminate(final Game game, final GameCommand gameCommand) { | ||
if (gameCommand.isEndCommand()) { | ||
gameService.saveGame(game); | ||
} | ||
} | ||
|
||
private void playTurn(final Board board) { | ||
private void executeTurn(final Game game) { | ||
Position source = Position.of(inputView.getPosition()); | ||
Position target = Position.of(inputView.getPosition()); | ||
|
||
board.tryMove(source, target); | ||
outputView.printBoard(board); | ||
game.move(source, target); | ||
outputView.printBoard(game.getBoard()); | ||
} | ||
|
||
private void viewScore(final Map<Position, Piece> board) { | ||
Referee referee = new Referee(board); | ||
|
||
double blackTeamScore = referee.calculateScore(Color.BLACK); | ||
outputView.printScore(blackTeamScore, Color.BLACK); | ||
double whiteTeamScore = referee.calculateScore(Color.WHITE); | ||
outputView.printScore(whiteTeamScore, Color.WHITE); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,46 @@ | ||
package chess.domain.board; | ||
|
||
import chess.domain.piece.Empty; | ||
import chess.domain.piece.Piece; | ||
import chess.domain.piece.PieceType; | ||
import chess.domain.position.Position; | ||
import java.util.Collections; | ||
import java.util.Map; | ||
|
||
public class Board { | ||
|
||
private final BoardInitializer boardInitializer; | ||
private final Map<Position, Piece> board; | ||
|
||
public Board(final BoardInitializer boardInitializer) { | ||
this.boardInitializer = boardInitializer; | ||
this.board = boardInitializer.initialize(); | ||
} | ||
|
||
public void tryMove(final Position source, final Position target) { | ||
Piece piece = board.get(source); | ||
if (piece.canMove(source, target, getBoard())) { | ||
move(source, target, piece); | ||
return; | ||
public boolean tryMove(final Position source, final Position target) { | ||
Piece sourcePiece = board.get(source); | ||
if (sourcePiece.canMove(source, target, board)) { | ||
move(source, target); | ||
return true; | ||
} | ||
|
||
throw new IllegalArgumentException("이동이 불가능한 위치입니다."); | ||
return false; | ||
} | ||
|
||
private void move(final Position source, final Position target) { | ||
board.put(target, board.get(source)); | ||
board.put(source, Empty.getInstance()); | ||
} | ||
|
||
private void move(final Position source, final Position target, final Piece piece) { | ||
board.put(target, piece); | ||
board.put(source, Piece.getEmptyPiece()); | ||
public boolean isKingKilled() { | ||
int kingCount = (int) board.entrySet().stream() | ||
.filter(entry -> entry.getValue().getPieceType() == PieceType.KING) | ||
.count(); | ||
return kingCount < 2; | ||
} | ||
|
||
public Map<Position, Piece> getBoard() { | ||
return Collections.unmodifiableMap(board); | ||
} | ||
|
||
public Piece get(final Position source) { | ||
return board.get(source); | ||
} | ||
} |
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.
현재는 게임의 턴과 기물별 위치를 저장하고 있는데요,
그 외에도 게임 명령어가 어떻게 입력되었는지를 적재하는 방식도 있을 것 같아요.
몰리가 선택해주신 방법과 위 방법은 각각 어떤 장단점이 있고, 어떤 상황에 적용이 적합할까요?
혹은 두 가지 모두 저장하는 일도 있을까요?
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.
제가 생각하기에는 다음과 같습니다.
[게임의 턴과 기물별 위치만 저장하는 방식]
[게임 명령어가 어떻게 입력되었는지를 적재하는 방식]
[두 가지 모두 저장]
게임을 빠르게 진행하면서 게임의 진행 과정을 상세히 기록할 수 있는 장점을 모두 활용하려고 할 경우, 두 가지 모두를 저장할 수 있을 것 같습니다..!
또 실행 순서가 필요한 요구사항으로 변경되지 않는다는 보장이 없기 때문에 가능한 둘 다 저장하는 것이 좋을 것 같다는 생각이 듭니다..!
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.
"하나의 게임진행 데이터지만 필요에 의해 여러가지 방식으로 나누어 적재를 할 수도 있다." 라는 메세지를 전달드리고 싶었어요 👍
추후 프로젝트를 진행할 때도 이 점을 참고해서 시스템 복잡도를 낮추는 경험을 해보시면 좋겠네요 😄 👍