-
Notifications
You must be signed in to change notification settings - Fork 0
[체스 - 3, 4 단계] 리비(이근희) 미션 제출합니다. #17
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
base: libienz
Are you sure you want to change the base?
Changes from all commits
fcbf2e3
72d8cf8
c3cae93
61d679f
ce8bffc
7b5c587
60e59aa
7367eb1
40c5e33
6d24abb
7afc4bc
270f24e
43a09ac
013ac29
e185bf1
243e8b0
0cdc887
47f2d6a
ebe16a8
16826b3
fd7f007
1929dc1
cc66773
5d549ce
78ad985
8781657
2a01371
ca9b473
21df77e
6bd2cd1
03702e7
5a49e74
2e9fabc
ed7939e
df94333
5219281
92e8d10
c079e96
e6f0d07
6c386fd
74108b0
fb2c817
9f787d6
30d43b5
dcda05d
09fec55
3b201cf
8ba88ff
f39f6f1
54e348d
20cf64f
75d9ebc
f3be8e8
44b50b6
65af47f
083ca2e
4e19ad8
3cfa820
2db4eb5
c861063
d9dfcb2
3fe6cf2
1e26dc3
f960aba
de67de5
5462f0c
661203a
21b7459
a6d4aff
02ebd2b
f2b0d15
9c32053
66ac4b2
059b37b
84a4043
7c2e131
0b5b6ec
6cb54fe
27c723b
8e978c4
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 |
|---|---|---|
| @@ -1,70 +1,84 @@ | ||
| # java-chess | ||
|
|
||
| ## 체스 게임 설명 | ||
| ### 입력 요구사항 | ||
|
|
||
| - 체스 게임은 화이트 팀과 블랙 팀으로 나뉜다 | ||
| - 체스 게임이 시작되면 화이트 팀부터 한 수씩 턴이 진행된다 | ||
| - [x] 체스 게임을 시작하는 명령어를 입력받을 수 있다. | ||
| - [x] 체스 게임을 종료하는 명령어를 입력받을 수 있다. | ||
| - [x] 체스 말을 이동하는 명령어를 입력받을 수 있다. | ||
| - [x] 각 진영의 점수를 확인하는 명령어를 입력받을 수 있다. | ||
| - [x] 명령어 입력시 형식에 맞는 입력이 들어오지 않으면 예외를 발생시킨다. | ||
|
|
||
| ## 1-2단계 요구사항 | ||
| ### 출력 요구사항 | ||
|
|
||
| 콘솔 UI에서 체스 게임을 할 수 있는 기능을 구현한다. | ||
| 1단계는 체스 게임을 할 수 있는 체스판을 초기화한다. | ||
| 체스판에서 말의 위치 값은 가로 위치는 왼쪽부터 a ~ h이고, 세로는 아래부터 위로 1 ~ 8로 구현한다. | ||
| - [x] 체스판의 초기 상태를 출력할 수 있다 | ||
| - [x] 매 턴마다 최신화된 체스판의 상태를 출력할 수 있다 | ||
| - [x] 체스판에서 각 진영은 대문자(검은색)와 소문자(흰색)로 출력한다. | ||
|
|
||
| ### 입력 요구사항 | ||
| ### 도메인 요구사항 | ||
|
|
||
| #### 기물 | ||
|
|
||
| - [x] 기물들은 화이트 또는 블랙의 팀을 가진다. | ||
| - [x] 기물들은 각각의 행마법에 따라 이동할 수 있다 | ||
|
|
||
| ``` | ||
| - 룩은 직선으로 이동할 수 있다 | ||
| - 비숍은 대각선으로 이동할 수 있다 | ||
| - 퀸은 직선/대각선으로 이동할 수 있다 | ||
| - 룩과 비숍, 퀸은 이동하는 경로에 기물이 존재하면 이동할 수 없다. | ||
| - 킹은 방향과 무관하게 1칸 이동할 수 있다 | ||
| - 나이트는 알파벳 L자 모양으로 앞으로 두칸 이동한 다음 왼쪽, 오른쪽 으로 한칸 움직일 수 있다 | ||
| - 폰은 초기 상태에서 한칸 또는 두칸씩 전진할 수 있다 | ||
| - 폰은 초기 상태에서 움직인 이후에는 한칸씩만 전진할 수 있다 | ||
| - 폰은 상대 기물이 한칸 대각선에 있다면, 이동할 수 있다 | ||
| - 모든 기물은 도착지에 같은 팀의 기물이 있다면 이동할 수 없다 | ||
| ``` | ||
|
|
||
| #### 체스 보드 초기화 | ||
|
|
||
| - [x] 체스 게임을 시작할지 여부를 입력받을 수 있다. | ||
| - [x] 체스 게임을 종료할지 여부를 입력받을 수 있다. | ||
| - [x] 체스 말의 이동정보를 입력받을 수 있다 | ||
| - [x] 게임 시작시 체스판을 초기화할 수 있다. | ||
| - [x] 체스판의 초기상태는 다음과 같다. | ||
| ``` | ||
| move b2 b3 | ||
| RNBQKBNR | ||
| PPPPPPPP | ||
| ........ | ||
| ........ | ||
| ........ | ||
| ........ | ||
| pppppppp | ||
| rnbqkbnr | ||
| ``` | ||
| - [x] 요구하는 형식의 입력이 들어오지 않으면 예외를 발생시킨다. | ||
| - [x] 체스판의 열은 왼쪽부터 a-h까지의 알파벳으로 이루어져 있다. | ||
| - [x] 체스판의 행은 밑부터 1-8까지의 숫자로 이루어져 있다. | ||
|
|
||
| ### 출력 요구사항 | ||
| #### 체스 보드 | ||
|
|
||
| - [x] 체스판의 상태를 출력할 수 있다. | ||
| - [x] 체스판의 초기 상태를 출력할 수 있다 | ||
| - [x] 매 턴마다 최신화된 체스판의 상태를 출력할 수 있다 | ||
| - [x] 체스판에서 각 진영은 대문자(검은색)와 소문자(흰색)로 출력한다. | ||
| - [x] 체스보드 상태를 업데이트 할 수 있다 | ||
| - [x] 기물들의 행마법을 검증할 수 있다 | ||
| - [x] 기물들을 이동시킬 수 있다. | ||
| - [x] 기물들의 위치는 체스보드 범위를 벗어날 수 없다. | ||
| - [x] 기물들이 이동할 수 없다면 기물의 위치를 옮기지 않는다 | ||
|
|
||
| ### 도메인 요구사항 | ||
| #### 체스 게임 | ||
|
|
||
| - [x] 체스 게임은 백팀의 이동으로 시작해야 한다. | ||
| - [x] 기물의 움직임 마다 자신의 턴인지 검증할 수 있어야 한다. | ||
| - [ ] 킹이 잡힌 경우 게임을 끝낼 수 있어야 한다. | ||
|
|
||
| #### 점수 계산 | ||
|
|
||
| - [x] 체스 프로그램에서 현재까지 남아 있는 말에 따라 점수를 계산할 수 있어야 한다. | ||
|
|
||
| ``` | ||
| Queen은 9점 | ||
| Rook은 5점 | ||
| Bishop은 3점 | ||
| Knight는 2.5점 | ||
| Pawn의 기본 점수는 1점, 같은 세로줄에 같은 색의 폰이 있는 경우는 0.5점으로 계산 | ||
| King은 점수가 없음 (잡히는 경우 게임 끝) | ||
| ``` | ||
|
|
||
| #### 이어 하기 | ||
|
|
||
| - [x] 체스 보드 초기화 | ||
| - [x] 게임 시작시 체스판을 초기화할 수 있다. | ||
| - [x] 체스판의 초기상태는 다음과 같다. | ||
| ``` | ||
| RNBQKBNR | ||
| PPPPPPPP | ||
| ........ | ||
| ........ | ||
| ........ | ||
| ........ | ||
| pppppppp | ||
| rnbqkbnr | ||
| ``` | ||
| - [x] 체스판의 열은 왼쪽부터 a-h까지의 알파벳으로 이루어져 있다. | ||
| - [x] 체스판의 행은 밑부터 1-8까지의 숫자로 이루어져 있다. | ||
| - [x] 기물들은 화이트 또는 블랙의 색깔을 가진다. | ||
|
|
||
| - [x] 기물 이동 | ||
| - [x] 기물들의 위치는 체스보드 범위를 벗어날 수 없다. | ||
| - [x] 기물들은 각자의 행마법을 따라 이동할 수 있다 | ||
| - [x] 룩은 직선으로 이동할 수 있다 | ||
| - [x] 비숍은 대각선으로 이동할 수 있다 | ||
| - [x] 퀸은 직선/대각선으로 이동할 수 있다 | ||
| - [x] 킹은 방향과 무관하게 1칸 이동할 수 있다 | ||
| - [x] 나이트는 알파벳 L자 모양으로 앞으로 두칸 이동한 다음 왼쪽, 오른쪽 으로 한칸 움직일 수 있다 | ||
| - [x] 폰의 행마법 | ||
| - [x] 폰은 초기 상태에서 한칸 또는 두칸씩 전진할 수 있다 | ||
| - [x] 폰은 초기 상태에서 움직인 이후에는 한칸씩만 전진할 수 있다 | ||
| - [x] 상대 기물이 한칸 대각선에 있다면, 이동할 수 있다 | ||
|
|
||
| - [x] 체스 보드 | ||
| - [x] 체스보드 상태를 업데이트 할 수 있다 | ||
| - [x] 기물들이 이동할 수 있다면 기물의 위치를 옮긴다 | ||
| - [x] 기물들이 이동할 수 없다면 기물의 위치를 옮기지 않는다 | ||
| - [x] 도착지에 같은 팀의 기물이 있다면 이동할 수 없다 | ||
| - [x] 비숍/룩/퀸은 이동 경로에 다른 기물이 있다면 이동할 수 없다 | ||
|
|
||
| - [ ] 애플리케이션을 재시작하더라도 이전에 하던 체스 게임을 다시 시작할 수 있어야 한다. | ||
|
|
| 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,38 +1,31 @@ | ||
| package chess.controller; | ||
|
|
||
| import chess.controller.command.Command; | ||
| import chess.domain.ChessGame; | ||
| import chess.domain.board.ChessBoard; | ||
| import chess.domain.board.ChessBoardCreator; | ||
| import chess.controller.command.ExecuteResult; | ||
| import chess.service.ChessGameService; | ||
| import chess.view.InputView; | ||
| import chess.view.OutputView; | ||
|
|
||
| public class ChessGameController { | ||
| private final InputView inputView; | ||
| private final OutputView outputView; | ||
| private final ChessGameService chessGameService; | ||
|
|
||
| public ChessGameController(InputView inputView, OutputView outputView) { | ||
| public ChessGameController(InputView inputView, OutputView outputView, ChessGameService chessGameService) { | ||
| this.inputView = inputView; | ||
| this.outputView = outputView; | ||
| this.chessGameService = chessGameService; | ||
| } | ||
|
|
||
| public void run() { | ||
| outputView.printStartMessage(); | ||
| Command command = inputView.readCommand(); | ||
| if (command.isNotStartCommand()) { | ||
| return; | ||
| } | ||
| chessGameService.startChessGame(); | ||
|
|
||
| ChessGame chessGame = initializeChessGame(); | ||
| while (command.isNotEndCommand()) { | ||
| command.execute(chessGame, outputView); | ||
| command = inputView.readCommand(); | ||
| ExecuteResult result; | ||
| do { | ||
| Command command = inputView.readCommand(); | ||
| result = command.execute(chessGameService, outputView); | ||
| } | ||
| } | ||
|
|
||
| private ChessGame initializeChessGame() { | ||
| ChessBoardCreator chessBoardCreator = new ChessBoardCreator(); | ||
| ChessBoard chessBoard = chessBoardCreator.create(); | ||
| return new ChessGame(chessBoard); | ||
| while (result.isSuccess() && result.isNeedNextCommand() && chessGameService.isChessGameNotEnd()); | ||
| } | ||
| } | ||
|
Member
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. Controller의 역할 일부를 Command로 분리한 부분이 인상깊네요! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,8 @@ | ||
| package chess.controller.command; | ||
|
|
||
| import chess.domain.ChessGame; | ||
| import chess.service.ChessGameService; | ||
| import chess.view.OutputView; | ||
|
|
||
| public interface Command { | ||
| void execute(ChessGame chessGame, OutputView outputView); | ||
|
|
||
| boolean isNotEndCommand(); | ||
|
|
||
| boolean isNotStartCommand(); | ||
| ExecuteResult execute(ChessGameService chessGameService, OutputView outputView); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,11 @@ | ||
| package chess.controller.command; | ||
|
|
||
| import chess.domain.ChessGame; | ||
| import chess.service.ChessGameService; | ||
| import chess.view.OutputView; | ||
|
|
||
| public class EndCommand implements Command { | ||
| @Override | ||
| public void execute(ChessGame chessGame, OutputView outputView) { | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isNotEndCommand() { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isNotStartCommand() { | ||
| return true; | ||
| public ExecuteResult execute(ChessGameService chessGameService, OutputView outputView) { | ||
| return new ExecuteResult(true, false); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package chess.controller.command; | ||
|
|
||
| public class ExecuteResult { | ||
| private final boolean success; | ||
| private final boolean needNextCommand; | ||
|
|
||
| public ExecuteResult(boolean success, boolean needNextCommand) { | ||
| this.success = success; | ||
| this.needNextCommand = needNextCommand; | ||
| } | ||
|
Comment on lines
+7
to
+10
Member
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. boolean 타입 변수 두개가 연속으로 나와서, 아주 헷갈릴 것 같아요. 래핑 하는 것이 나을 것 같아요. |
||
|
|
||
| public boolean isSuccess() { | ||
| return success; | ||
| } | ||
|
|
||
| public boolean isNeedNextCommand() { | ||
| return needNextCommand; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,14 @@ | ||
| package chess.controller.command; | ||
|
|
||
| import chess.domain.ChessGame; | ||
| import chess.dto.BoardDto; | ||
| import chess.service.ChessGameService; | ||
| import chess.view.OutputView; | ||
|
|
||
| public class StartCommand implements Command { | ||
| @Override | ||
| public void execute(ChessGame chessGame, OutputView outputView) { | ||
| outputView.printChessBoardMessage(chessGame.getChessBoard()); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isNotEndCommand() { | ||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isNotStartCommand() { | ||
| return false; | ||
| public ExecuteResult execute(ChessGameService chessGameService, OutputView outputView) { | ||
| BoardDto boardDto = chessGameService.startChessGame(); | ||
| outputView.printChessBoardMessage(boardDto); | ||
| return new ExecuteResult(true, true); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package chess.controller.command; | ||
|
|
||
| import chess.dto.ScoreStatusDto; | ||
| import chess.service.ChessGameService; | ||
| import chess.view.OutputView; | ||
|
|
||
| public class StatusCommand implements Command { | ||
|
|
||
| @Override | ||
| public ExecuteResult execute(ChessGameService chessGameService, OutputView outputView) { | ||
| ScoreStatusDto scoreStatusDto = chessGameService.calculateScoreStatus(); | ||
| outputView.printStatusMessage(scoreStatusDto); | ||
| return new ExecuteResult(true, true); | ||
| } | ||
| } | ||
|
Comment on lines
+7
to
+15
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. 나도 이런 형식의 Command 도입을 고려했었는데 각 커멘드마다 로직이 여러 파일로 분리되는 것 같아 꺼려했었어
Member
Author
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. 나만의 커맨드 패턴에 대한 소감있지 ㅋㅋ 우선 나는 만약에 그냥 명령의 타입만 확인하고 컨트롤러 코드에서 다음과 같이 분기한다면 그건 책임이 잘못된 것이라고 생각해. // 컨트롤러 내부 코드
if(command == Command.START) {
// do someting
}
if(command == Command.END) {
// do someting
}
if(command == Command.STATUS) {
// do someting
}
if(command == Command.MOVE) {
// do someting
}명령이라는 도메인을 정의했을 때는 응당 해당 명령에 대한 동작을 응집할 수 있어야 한다고 생각했어 |
||
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.
나도 Service를 이용했는데, 이 부분에서 필드를 세 개 사용한다는 지적을 받았어.
어떻게 이야기 해야 될까?
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.
나도 어떻게 해야 할지 속으로만 생각했는데 컨트롤러를 호출하는 Application 클래스를 요청자로써 새로 정의할 것 같아
Application을 요청자로 정의하여 InputView와 OutputView를 할당하고 Application이 컨트롤러에 요청할 때는 입력받은 String 혹은 Command로 요청하도록 하는 거지.
이렇게 하면 컨트롤러는 들어오는 요청과 요청을 위임할 서비스 레이어만 알게되고 어플리케이션 클래스가 InputView와 OutputView를 아는 요청자가 된다는 측면에서 하나의 해결책이 될 수 있지 않을까 생각함 👍