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

[3, 4단계 - 체스] 몰리(김지민) 미션 제출합니다. #791

Merged
merged 118 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
24a97a3
fix: 픽스처 사용하여 변경한 지역 변수에 대해 레거시 제거
jminkkk Mar 28, 2024
401b894
refactor: obstacle 패키지를 domain아래로 위치 수정
jminkkk Mar 28, 2024
2fb03b5
refactor: 타입 별 장애물에 대한 규칙 구현체 생성
jminkkk Mar 28, 2024
fae3909
docs(README.md): 추가된 요구사항 명세 분석 작성 및 설계 일부분 변경
jminkkk Mar 28, 2024
c8b8d42
feat(Turn): 게임 시작 시 턴은 검정팀부터 시작하는 기능 구현
jminkkk Mar 28, 2024
ae20320
test(Turn): 해당 색상의 팀 차례인지 확인하는 테스트 추가
jminkkk Mar 28, 2024
ed77e6c
refactor(Turn): 턴 전략을 받아 객체를 생성하는 로직 추가 및 검정팀 먼저인 턴 전략 구현
jminkkk Mar 28, 2024
a11ca19
refactor(Turn): 턴에 color를 받는 생성자 추가 및 턴 생성 전략 제거
jminkkk Mar 29, 2024
51ed08a
test(Turn): 다음 차례를 반환하는 기능 구현
jminkkk Mar 29, 2024
bdb1ef0
refactor(Color): 같은 색상인지 확인하는 메서드의 인자를 Piece에서 Color로 수정
jminkkk Mar 29, 2024
33700c3
refactor(Turn): 누구의 차례인지 확인하는 로직에서 piece를 받도록 수정
jminkkk Mar 29, 2024
268ac49
fix(BoardTest): 이동을 검사하는 테스트에서 턴을 고려하여 테스트 Piece 변경
jminkkk Mar 29, 2024
a5185cd
refactor(Board): 턴을 체크하는 기능 구현
jminkkk Mar 29, 2024
dc13a62
refactor(EnemyExistPolicy): 타겟이 적인지 판단하는 로직을 Piece에서 EnemyExistPolicy…
jminkkk Mar 29, 2024
4183c3d
docs(README.md): 요구사항 객체 재 설계
jminkkk Mar 29, 2024
96a6038
refactor(PieceType): PieceType에서 ObstacleRule 제거
jminkkk Mar 29, 2024
ce8a6a3
refactor(obstaclerule/): 각 피스별 ObstacleRule 구현체 제거
jminkkk Mar 29, 2024
be855f4
refactor(Position): 두 포지션의 file을 비교해 rank만 이동한 것인지 체크하는 기능을 Position으…
jminkkk Mar 30, 2024
329b27a
refactor(Piece): 추상 클래스로 변경
jminkkk Mar 30, 2024
f6db0b8
refactor: ObstacleRule을 Attacker로 이름 변경 및 인터페이스로 변경
jminkkk Mar 30, 2024
9bcfd67
refactor(Empty): Piece를 상속 받는 Empty 객체 생성
jminkkk Mar 30, 2024
dd21d25
refactor(Empty): Empty를 싱글톤으로 사용하도록 변경
jminkkk Mar 30, 2024
5cd033a
refactor(Attacker): Attacker의 구현체들을 Attacker와 Piece을 상속받도록 변경
jminkkk Mar 30, 2024
8b7073b
refactor(Attacker): 자기자신을 제거하는 로직 Attacker에서 구현체들로 변경
jminkkk Mar 30, 2024
16ce484
refactor(Bishop): DirectionAttackPiece를 상속받는 Bishop 객체 구현 및 관련 테스트 Pi…
jminkkk Mar 30, 2024
be7de57
refactor(King): DirectionAttackPiece를 상속받는 King 객체 구현 및 관련 테스트 Piece에…
jminkkk Mar 30, 2024
d9477a4
refactor(Knight): DirectionAttackPiece를 상속받는 Knight 객체 구현 및 관련 테스트 Pi…
jminkkk Mar 30, 2024
aad13c2
refactor(Queen): DirectionAttackPiece를 상속받는 Queen 객체 구현 및 관련 테스트 Piec…
jminkkk Mar 30, 2024
df9bd37
refactor(Rook): DirectionAttackPiece를 상속받는 Rook 객체 구현 및 관련 테스트 Piece에…
jminkkk Mar 30, 2024
a1df2a4
refactor(Pawn): DiagonalAttackPiece를 상속받는 Pawn 객체 구현 및 관련 테스트 Piece에서 이동
jminkkk Mar 30, 2024
c4c9309
fix(Piece): Piece가 아닌 각 말의 구현체들로 변경
jminkkk Mar 30, 2024
bb5bc05
feat(Piece): 이동가능한지 확인하는 메서드를 추상 메서드로 변경 및 equals와 hashcode 구현
jminkkk Mar 30, 2024
71541df
refactor(piece/attacker/): AttackPiece의 구현체에 대한 패키지 위치 수정 및 이름 변경
jminkkk Mar 30, 2024
16daf5b
feat(ScoreRule): 점수 규칙에 대한 추상 클래스 생성
jminkkk Mar 30, 2024
9cd97e5
feat(NormalScoreRule): 기본 점수에 곱으로 계산하는 점수 규칙 로직 구현
jminkkk Mar 30, 2024
a22bf90
feat(PawnScoreRule): 폰에 대한 점수 규칙 생성 및 같은 줄에 같은 색의 폰이 있는 경우 점수 계산 기능 구현
jminkkk Mar 30, 2024
9763153
test(PawnScoreRule): 같은 줄에 폰이 없는 경우 점수 계산 기능 구현
jminkkk Mar 30, 2024
be5957b
feat(NoScoreRule): 점수가 없는 경우 0을 반환하는 NoScoreRule 구현
jminkkk Mar 30, 2024
5147bed
feat(PieceType): 타입별 ScoreRule 구현 및 Pawn에 대한 점수 테스트 작성
jminkkk Mar 30, 2024
64d8039
test(PieceType): 폰을 제외한 말들의 점수 테스트 작성
jminkkk Mar 30, 2024
9e89a49
feat(Referee): 팀별 피스 목록을 점수 규칙에 맞게 점수를 계산하는 Referee 객체 구현
jminkkk Mar 30, 2024
ebd9b84
fix(Board): turn을 불변에서 변경
jminkkk Mar 30, 2024
860d072
feat(GameCommand): 현재 스코어를 확인할 수 있는 STATUS 명령어 추가
jminkkk Mar 30, 2024
6bc0880
fix(PawnScoreRule): 같은 file에 있는 개수를 계산하는 메서드 올바르게 수정
jminkkk Mar 30, 2024
28869f3
feat(ChessGameController): 기물별 점수를 출력하는 기능 구현
jminkkk Mar 30, 2024
4f759c7
feat(OutputView): 현재 팀의 점수를 출력하는 메서드 구현
jminkkk Mar 30, 2024
c1b5f4a
feat(Board): King이 잡힐 시에 게임이 종료되는 기능 구현
jminkkk Mar 31, 2024
d77e89a
feat(ChessGameController): 게임이 끝났는지 확인하고 진행하도록 구현
jminkkk Mar 31, 2024
603a772
chore(build.gradle): mysql 의존성 추가
jminkkk Mar 31, 2024
9dc16f9
feat(OuputView): king이 잡혀 게임 이 종료되었을 때 출력문 추가
jminkkk Mar 31, 2024
afac83e
chore(docker/): docker-compose.yml 작성
jminkkk Mar 31, 2024
f225430
test(DatabaseConfig): 드라이버 연결 설정 파일 작성
jminkkk Mar 31, 2024
36b1541
feat(PieceDao): Piece와 해당 Piece의 Position를 위한 Dao 구현
jminkkk Mar 31, 2024
b6f4a58
feat(PieceDto): piece model, dao간 변환을 위한 dto 생성 및 File, Rank에 변환을 위한 …
jminkkk Mar 31, 2024
4fd6574
feat(TurnDao): Turn를 위한 Dao 구현
jminkkk Mar 31, 2024
b364412
feat(TurnDto): turn model, dao간 변환을 위한 dto 생성
jminkkk Mar 31, 2024
6c61b9a
test(FakeDao): 테스트용 FakeDao 생성
jminkkk Mar 31, 2024
1f91692
feat(ddl.sql): ddl 문 추가
jminkkk Mar 31, 2024
5a0dbc6
feat(Board, BoardInitializer): 저장된 게임을 확인하고 여부를 받는 게임 로직 추가 및 BoardIn…
jminkkk Mar 31, 2024
041202b
feat(ChessGameService): Dao를 통해 DB 관련 로직을 수행하는 Service 구현
jminkkk Mar 31, 2024
4e426bb
feat(ChessGameController): 재시작 여부를 받고 저장된 게임을 실행하는 컨트롤러 로직 작성
jminkkk Mar 31, 2024
e2a39ba
refactor: getter 대신 객체에게 물어보도록 수정
jminkkk Mar 31, 2024
9fc8bee
fix(FakePieceDao): LinkedList로 변경
jminkkk Mar 31, 2024
4672b09
refactor(ChessGameService): 전체 내역 삭제하는 메서드 이름 변경 및 PieceDao 필드를 인터페이스…
jminkkk Mar 31, 2024
38c9b93
test(ChessGameService): Fake 객체를 활용하여 Servive 단 로직 테스트
jminkkk Mar 31, 2024
4470230
fix(ChessGameServiceTest): 저장된 PieceDto의 순서 상관없이 원소만 확인
jminkkk Mar 31, 2024
b2a038f
fix(ddl.sql): 불필요한 쿼리문 제거
jminkkk Apr 1, 2024
155a92e
test(Position): rank 이동에 대해 참거짓을 반환하는 테스트 작성
jminkkk Apr 2, 2024
f7c678c
refactor(GameCommand): GameCommand에게 게임을 진행하는 명령어인지 물어보도록 수정
jminkkk Apr 2, 2024
2b00dc3
refactor(InputView): 저장된 게임을 실행하는 로직에서 입력된 문구가 일치하는지 처리를 InputView로 이…
jminkkk Apr 2, 2024
d7412f5
refactor(Turn): 게임의 차례를 나타내는 Turn 객체 제거
jminkkk Apr 2, 2024
39184ca
refactor(GameStatus): 게임의 상태를 나타내기 위한 인터페이스 생성
jminkkk Apr 2, 2024
f389cbd
feat(Running): 게임이 진행 중인 상태를 나타내는 Running 추상 클래스 생성
jminkkk Apr 2, 2024
2218494
feat(Running): 게임 종료를 확인하는 메서드 구현
jminkkk Apr 2, 2024
b885bf1
feat(BlackTurn): 검정 팀이 차례인 상태에 따른 행위 구현
jminkkk Apr 2, 2024
8a7699f
feat(WhiteTurn): 화이트 팀이 차례인 상태에 따른 행위 구현
jminkkk Apr 2, 2024
235792c
feat(Finished): 종료 상태에 따른 행위 구현
jminkkk Apr 2, 2024
3c0cc21
test(WhiteTurn, BlackTurn): 현재 차례에 해당하는 색을 올바르게 반환하는지 테스트
jminkkk Apr 2, 2024
86ba136
feat(Game): 게임의 진행을 관리하는 Game 클래스 구현
jminkkk Apr 2, 2024
a6c6b9a
refactor(Board): 턴 및 게임의 상태를 관리하는 로직 제거
jminkkk Apr 2, 2024
611a76d
refactor(TurnDto): Turn 객체가 아닌 색상을 받아 전달하도록 수정
jminkkk Apr 2, 2024
3f858ee
feat(OutputView, ColorDisplay): 저장된 게임 실행 시 기존 차례에 해당하는 색을 출력하는 메서드 및…
jminkkk Apr 2, 2024
cf27f9b
refactor(ChessGameController, ChessGameService): Board가 아닌 Game을 실행하도…
jminkkk Apr 2, 2024
e45545f
fix(PieceDto): 타입에 맞는 객체 반환 시, 다른 타입으로 생성되는 피스 수정
jminkkk Apr 2, 2024
a2129d5
fix(Empty): 생성자를 private로 변경
jminkkk Apr 2, 2024
51b1699
fix(Finished): Finished는 Running을 상속받지 않도록 수정
jminkkk Apr 2, 2024
de49715
fix(InputView, OutputView): 저장된 게임의 실행 여부를 묻는 출력문을 입력받기 전에 출력하도록 위치 수정
jminkkk Apr 2, 2024
16a8e8a
refactor(ChessGameService): 게임을 저장하는 메서드의 이름을 변경
jminkkk Apr 2, 2024
b0c8f1a
fix(BoardTest): 상태패턴 도입으로 boolean을 반환하는 메서드의 테스트도 수정
jminkkk Apr 2, 2024
3e5aec1
refactor(ChessGameController): 흐름이 보이도록 수정 및 추출하지 않아도 되는 메서드 합치기
jminkkk Apr 2, 2024
ee89cd4
refactor(ObstacleFinder): Attacker 에서 ObstacleFinder로 이름 변경
jminkkk Apr 2, 2024
498bfa5
refactor(AttackPiece): AttackPiece 구현체 제거 및 ObstacleRule만 상속받도록 수정
jminkkk Apr 2, 2024
b409982
refactor(MovementDirectionObstacleFinder): MovementDirectionObstacleF…
jminkkk Apr 2, 2024
a3f41aa
refactor(Empty): Piece를 상속받도록 수정
jminkkk Apr 2, 2024
dcb595e
refactor(Pawn): PawnObstacleFinder를 사용하여 움직임을 판단하도록 수정
jminkkk Apr 2, 2024
f9ac2f8
fix(KnightTest): 시작 위치가 보드 목록에서 누락되어 있던 것 수정
jminkkk Apr 2, 2024
7345e75
fix(KnightObstacleFinder, Knight): 타겟을 비교하여 나이트의 규칙에 맞는 장애물을 반환하는 Kni…
jminkkk Apr 2, 2024
2404075
fix(Knight): 잘못 임포트된 패키지 변경
jminkkk Apr 2, 2024
3070131
refactor(Piece): 같은 팀인지 확인하는 메서드 긍정형으로 변경
jminkkk Apr 2, 2024
89f6380
fix(game/): 게임 패키지 생성 및 board 패키지에서 game 관련 객체 이동
jminkkk Apr 2, 2024
51d06e1
fix(ChessGameController): start 여러번 수행 시 end가 되지 않는 이슈 해결 및 전체 메서드명 일…
jminkkk Apr 2, 2024
0c46af2
refactor(ChessGameController): 게임이 진행중인지 확인하는 메서드명 수정
jminkkk Apr 3, 2024
fd45dee
refactor(GameCommand): GameCommand에게 특정 명령어인지 질문하도록 수정
jminkkk Apr 4, 2024
aec228f
refactor(FakeDao): 테스트를 위한 Fake 객체의 위치를 test/아래로 이동
jminkkk Apr 4, 2024
19d56a1
refactor(DatabaseConfig): db 타임존 Asia/Seoul로 설정
jminkkk Apr 4, 2024
6dec859
refactor(docker-compose.yml): 불필요한 db 유저 정보 제거
jminkkk Apr 4, 2024
ca7ebd7
feat(PieceDao): Piece 테이블에 로우가 하나라도 존재하는지 조회하는 기능 추가
jminkkk Apr 4, 2024
30e78e4
test(PieceDao): Pieces가 DB에 존재하는지 묻는 테스트 작성 및 FakePieceDao에 existPiec…
jminkkk Apr 4, 2024
fd3f758
feat(ChessGameService): 저장된 게임이 존재하는지 확인하는 메서드를 existPieces를 사용해 변경
jminkkk Apr 4, 2024
d2979f0
refactor(TurnDao): 턴 조회 시 단건 조회로 변경 및 TurnDao에서 턴 조회 시 Dto가 아닌 Color로…
jminkkk Apr 4, 2024
a415567
refactor(JdbcPieceDao, JdbcTurnDao):Dao의 구현체의 이름을 의미를 명확하게 이름 변경
jminkkk Apr 4, 2024
a2e7ba9
refactor(PieceDto): PieceDto 제거 및 기물 타입에 맞는 피스를 생성해주는 역할을 PieceFactor…
jminkkk Apr 4, 2024
ae7bb18
fix(JdbcPieceDao): 피스가 존재하는지 확인하는 Dao 메서드를 resultSet.next() 사용 후 값을 가…
jminkkk Apr 4, 2024
513120b
refactor(ddl.sql): 도커 실행 시 init되도록 ./db/mysql/init 아래로 이동 및 user에게 권한…
jminkkk Apr 4, 2024
3276d42
refactor(DatabaseConfig): root가 아닌 user라는 유저를 통해 접근하도록 다시 수정
jminkkk Apr 4, 2024
0522e16
style(DaoTest): 테스트 설명을 위한 DisplayName 추가
jminkkk Apr 4, 2024
3a44feb
refactor(JdbcDao): SQLException 발생 시 기존 예외 메시지도 함께 출력하도록 수정
jminkkk Apr 4, 2024
eea10af
refactor(repository/): dao 명칭을 repository로 변경
jminkkk Apr 7, 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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ dependencies {
testImplementation platform('org.assertj:assertj-bom:3.25.1')
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation('org.assertj:assertj-core')

runtimeOnly("com.mysql:mysql-connector-j:8.3.0")
}

java {
Expand Down
21 changes: 21 additions & 0 deletions docker/db/mysql/init/ddl.sql
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
);
Comment on lines +8 to +21
Copy link
Member

@Hyeon9mak Hyeon9mak Apr 6, 2024

Choose a reason for hiding this comment

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

현재는 게임의 턴과 기물별 위치를 저장하고 있는데요,
그 외에도 게임 명령어가 어떻게 입력되었는지를 적재하는 방식도 있을 것 같아요.

몰리가 선택해주신 방법과 위 방법은 각각 어떤 장단점이 있고, 어떤 상황에 적용이 적합할까요?
혹은 두 가지 모두 저장하는 일도 있을까요?

Copy link
Author

@jminkkk jminkkk Apr 7, 2024

Choose a reason for hiding this comment

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

제가 생각하기에는 다음과 같습니다.
[게임의 턴과 기물별 위치만 저장하는 방식]

  • 장점
    • 현재 상태만 저장하기 때문에 관리해야 하는 데이터의 양이 적다.
    • 바로 데이터를 불러와서 시작할 수 있어 초기 시작 시간이 짧다.
  • 단점
    • 어떤 차례를 통해 현재 상태가 되었는지 알 수 없다.
    • 요구사항이 변경되어, 무르기 기능이나 퀸의 첫 이동 체크 등이 추가되었을 경우 히스토리가 없기 때문에 구현이 곤란할 것 같다.
  • 어떤 상황에 적합할까
    • 히스토리가 필요하지 않는 요구사항일 경우
    • 게임의 진행 상태만 빠르게 복구하려는 경우

[게임 명령어가 어떻게 입력되었는지를 적재하는 방식]

  • 장점
    • 게임의 전체 내역을 관리할 수 있다.
    • 오히려 모든 명령어를 저장하기 때문에 턴이나, 기타 다른 정보를 저장하지 않아도 될 수 있다.
  • 단점
    • 게임 시작 시 매번 전체 명령어를 실행을 시켜야 하기 때문에 리소스 낭비나 초기 시작 시간이 발생할 수 있다.
  • 어떤 상황에 적합할까
    • 실행 순서가 필요한 요구사항일 경우(ex. 앞서 말한 무르기, 퀸의 첫 이동 체크 등등)

[두 가지 모두 저장]
게임을 빠르게 진행하면서 게임의 진행 과정을 상세히 기록할 수 있는 장점을 모두 활용하려고 할 경우, 두 가지 모두를 저장할 수 있을 것 같습니다..!

또 실행 순서가 필요한 요구사항으로 변경되지 않는다는 보장이 없기 때문에 가능한 둘 다 저장하는 것이 좋을 것 같다는 생각이 듭니다..!

Copy link
Member

Choose a reason for hiding this comment

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

"하나의 게임진행 데이터지만 필요에 의해 여러가지 방식으로 나누어 적재를 할 수도 있다." 라는 메세지를 전달드리고 싶었어요 👍
추후 프로젝트를 진행할 때도 이 점을 참고해서 시스템 복잡도를 낮추는 경험을 해보시면 좋겠네요 😄 👍

18 changes: 18 additions & 0 deletions docker/docker-compose.yml
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
43 changes: 37 additions & 6 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@

## 보드

- [x] 보드는 체스 말과 위치를 가진다.
- [x] 보드는 체스 말별 위치를 가진다.
- [x] 보드에서 체스 말을 이동시킬 수 있다.
- [x] 보드에서 체스 말을 이동할 수 없는 경우 예외가 발생한다.
- [x] 이동하려는 말의 팀이 현재 턴이여야 이동이 가능하다.
- [x] 보드에서 체스 말을 이동할 수 없는 경우 예외가 발생한다.
- [x] 체스 말과 위치 정보를 반환할 수 있다.
- [x] King이 잡힐 시에 게임이 종료된다.

### 게임 턴

- [x] 게임 시작 시 턴은 검정팀부터 시작한다.
- [x] 다음 차례를 반환한다.
- [x] 2팀이 턴을 번갈아가며 수행한다.
- [x] 해당 색상의 팀 차례인지 확인한다.

## 체스 말

- [x] 체스 말은 진영의 색깔과 종류를 가진다.
- [x] 체스 말은 말의 종류를 가진다.
- [x] 체스 말은 이동을 가진다.
- [x] 체스 말은 출발 위치, 도착 위치, 첫 이동 여부, 말의 위치 정보 목록을 바탕으로 움직일 수 있는지 확인한다.
- [x] 폰
- [x] 이동이 가능한 경우
Expand All @@ -38,7 +48,8 @@

## 말 종류

- [x] 체스 말은 이동을 가진다.
- [x] 체스 말 종류는 각각의 이동 목록을 가진다.
- [x] 체스 말 종류는 각각의 점수 규칙을 가진다.

## 이동

Expand Down Expand Up @@ -82,21 +93,41 @@
- [x] File값이 최소인지 확인한다.
- [x] File값이 최대인지 확인한다.

## 장애물 규칙
### 점수 규칙

- [x] 점수 규칙은 기본점수를 가진다.
- [x] 폰에 대한 점수 규칙은 다음과 같다.
- [x] 같은 세로 줄에 같은 색의 폰이 여러개 있는 경우, 각각 0.5점
- [x] 같은 세로 줄에 같은 색의 폰이 하나만 있는 경우, 1점(기본점수)
- [x] 폰을 제외한 다른 말들은 기본 점수 * 말의 개수이다.

## 심판

- [x] 팀별 피스 목록을 점수 규칙에 맞게 점수를 계산한다.

## 공격 유형

### 공격 공통

- [x] EMPTY가 아닌 Piece들의 위치 목록 조회
- [x] 목표 위치가 상대편 말일 경우, 공격할 수 있기 때문에 장애물 목록에서 제거
- [x] 출발 위치는 현재 자신의 위치이므로, 장애물 목록에서 제거

### 대각선 공격 시 (공격 공통 + 추가)
### 이동 방향으로 공격

- [x] EMPTY가 아닌 Piece들의 위치 목록 조회
- [x] 목표 위치가 상대편 말일 경우, 공격할 수 있기 때문에 장애물 목록에서 제거
- [x] 출발 위치는 현재 자신의 위치이므로, 장애물 목록에서 제거

### 이동 방향과 다른 대각선 공격

아래의 경우에 장애물 목록에 도착 위치 Piece를 추가한다.

- [x] 도착 위치가 상대편 말이지만 출발 위치와 도착 위치가 직선 이동일 경우
- [x] 도착 위치가 EMPTY이고 출발 위치와 도착 위치가 대각 이동일 경우

---

## 입출력

- [x] 입력 기능 구현
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/chess/Application.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package chess;

import chess.controller.ChessGameController;
import chess.repository.piece.JdbcPieceRepository;
import chess.repository.turn.JdbcTurnRepository;
import chess.service.ChessGameService;
import chess.view.InputView;
import chess.view.OutputView;

public class Application {
public static void main(String[] args) {
try {
ChessGameController chessGameController = new ChessGameController(new InputView(), new OutputView());
ChessGameController chessGameController = new ChessGameController(new InputView(), new OutputView(),
new ChessGameService(new JdbcPieceRepository(), new JdbcTurnRepository()));
chessGameController.start();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
Expand Down
106 changes: 86 additions & 20 deletions src/main/java/chess/controller/ChessGameController.java
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
Copy link
Member

Choose a reason for hiding this comment

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

service 라는 명칭을 사용한 이유가 있나요? 🤔

Copy link
Author

Choose a reason for hiding this comment

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

스프링을 사용할 때, 컨트롤러와 레포지토리 사이에서 비즈니스 로직을 처리하는 Service 계층을 사용했었는데요..!

제가 생각하기에 Service 계층의 역할은 크게 2가지라고 생각합니다!

  1. 비즈니스 로직 처리
  2. 로직에 맞는 DAO 호출

이번 미션에서 비즈니스 로직은 도메인에서 거의 처리가 되었기 때문에, 1번 역할을 수행하지는 않았는데요.
하지만 이번에 적용한 Service 객체가 2번 역할을 수행하는 용도와 닮아있다고 생각해서 Service라는 네이밍을 사용했습니다!

Copy link
Member

Choose a reason for hiding this comment

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

비즈니스 로직은 각각의 비즈니스 객체(domain 계층)가 수행할 수 있는 걸로 보여요.
그래야 비즈니스 변경 요구사항이 전달되었을 때 controller, service 패키지를 열어볼 필요 없이
domain 패키지 탐색을 시작으로 빠르게 수정할 대상을 찾아낼 수 있기 때문이에요.
(controller 가 view 와 domain 의 소통에만 집중해야하는 것과 같은 이유)

결국 service 계층은 2번처럼 비즈니스 로직과 영속 계층사이 소통만 담당하는 것이 이상적이겠네요!

Copy link
Author

Choose a reason for hiding this comment

The 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);
}
}
34 changes: 22 additions & 12 deletions src/main/java/chess/domain/board/Board.java
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);
}
}
Loading