Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
257a933
[1, 2단계 - 체스] 망쵸(김주환) 미션 제출합니다. (#712)
3Juhwan Mar 24, 2024
77cdad5
remove: 누락된 Turn 클래스 삭제
3Juhwan Mar 24, 2024
03ca8cf
docs: 기능 요구사항 작성
3Juhwan Mar 24, 2024
dd3359e
refactor: 테스트를 위한 Position 픽스쳐 추가
3Juhwan Mar 24, 2024
3721bdb
feat: Score 계산 클래스 추가
3Juhwan Mar 24, 2024
c82a41f
feat: Score 계산 클래스 추가
3Juhwan Mar 24, 2024
1666be6
feat: status 커맨드 추가
3Juhwan Mar 24, 2024
0563ffb
feat: king이 죽으면 게임 종료하는 기능 추가
3Juhwan Mar 24, 2024
fcb73d9
feat: DB ConnectionManager 구현
3Juhwan Mar 25, 2024
04b0745
feat: PieceDto 추가
3Juhwan Mar 25, 2024
3f7cb1c
chore: DB를 위한 환경 설정
3Juhwan Mar 25, 2024
e4e7951
feat: chess SQL문 추가
3Juhwan Mar 25, 2024
f47c296
feat: PieceDao 추가
3Juhwan Mar 25, 2024
ece313b
feat: 도메인에서 DTO로 변환하는 기능 추가
3Juhwan Mar 25, 2024
910d230
feat: 피스를 전체 조회하는 기능 추가
3Juhwan Mar 25, 2024
8f7258f
feat: 피스 개수를 조회하는 기능 추가
3Juhwan Mar 25, 2024
a2693af
refactor: view에 필요한 값 File 필드 삭제
3Juhwan Mar 25, 2024
9a3592a
rename: SQL 스크립트명 수정
3Juhwan Mar 25, 2024
1286a69
feat: turn SQL문 추가
3Juhwan Mar 25, 2024
805250d
docs: DB 저장에 대한 기능 요구사항 추가
3Juhwan Mar 25, 2024
e44402b
refactor: 테이블명 수정
3Juhwan Mar 25, 2024
e4c2406
refactor: 테이블명 수정
3Juhwan Mar 25, 2024
e7f427e
feat: TurnDao 추가
3Juhwan Mar 25, 2024
5819994
feat: 이전 게임 상태를 DB에서 불러오는 기능 구현
3Juhwan Mar 25, 2024
a045387
docs: 체스 게임 전반적인 흐름 재작성
3Juhwan Mar 25, 2024
68e36b8
rename: db, dao, dto 패키지 분리
3Juhwan Mar 25, 2024
56e6893
feat: DBService 추가
3Juhwan Mar 25, 2024
ad3ec11
feat: 이전 턴을 조회하는 기능 추가
3Juhwan Mar 25, 2024
7c04c5d
feat: 턴을 갱신하는 기능 추가
3Juhwan Mar 25, 2024
740d045
refactor: Controller 메서드 분리
3Juhwan Mar 25, 2024
0e2db44
feat: King이 잡히면 게임 데이터 삭제하는 기능 추가
3Juhwan Mar 25, 2024
345b08e
refactor: 커맨드 가공하는 책임을 InputView에서 CommandType으로 위임
3Juhwan Mar 26, 2024
b405445
refactor: DB table명 수정
3Juhwan Mar 26, 2024
5c46b6d
feat: 게임이 종료되면 점수를 출력하는 기능 추가
3Juhwan Mar 26, 2024
50ad35c
refactor: 컨트롤러 구조 수정
3Juhwan Mar 26, 2024
ddbfe11
fix: 게임 시작 안되는 버그 수정
3Juhwan Mar 26, 2024
657dd4c
refactor: JDBC 중복 코드 분리
3Juhwan Mar 27, 2024
e5652d1
rename: DAO 클래스 패키지 이동, 이름 수정
3Juhwan Mar 27, 2024
6aa638d
rename: DTO 패키지 분리
3Juhwan Mar 27, 2024
75338a7
refactor: 커맨드 생성과 검증에 대한 책임 분리
3Juhwan Mar 27, 2024
4b876b4
refactor: turn을 GameStatus로 대체, 예외 처리 로직 메서드 분리
3Juhwan Mar 28, 2024
a8150aa
refactor: GameStatus를 State으로 이름 변경
3Juhwan Mar 29, 2024
29c7961
refactor: GameStatus를 State으로 이름 변경
3Juhwan Mar 29, 2024
8d73e8c
refactor: ChessGame 생성, 상태 패턴 적용
3Juhwan Mar 30, 2024
e580d53
chore: docker 컨테이너 생성 시점에 스키마 생성되도록 설정
3Juhwan Mar 30, 2024
013c56e
style: 테스트명 포맷 변경 어노테이션 추가
3Juhwan Mar 30, 2024
e09324d
refactor: view 로직 static 변경, 영속화 계층 클래스명 수정
3Juhwan Mar 30, 2024
263a083
refactor: Position 주생성자를 부생성자로 변경
3Juhwan Mar 30, 2024
fb8f044
refactor: 불필요한 개행 삭제, 접근 제어자 수정
3Juhwan Mar 30, 2024
46b2487
test: 영속성 service 테스트에 모킹 적용
3Juhwan Mar 30, 2024
81bcc69
refactor: 명령어 실행 결과 메시지 출력 수정
3Juhwan Mar 30, 2024
3f0e0b1
remove: gitkeep 삭제
3Juhwan Mar 30, 2024
d7a9453
refactor: JdbcTemplate에 중복된 메서드 제거
3Juhwan Mar 30, 2024
d7f52e2
style: 불필요한 개행 삭제
3Juhwan Mar 30, 2024
8ff370c
docs: 추가 기능1 요구사항 추가
3Juhwan Mar 31, 2024
7e64983
feat: room 스키마 추가
3Juhwan Mar 31, 2024
d023be2
feat: RoomDao 추가
3Juhwan Mar 31, 2024
5a02d85
feat: GameRoomService 추가
3Juhwan Mar 31, 2024
bd5cf95
refactor: DTO 필드 타입 변경
3Juhwan Mar 31, 2024
126fb31
refactor: DAO에 GameId 파라미터 추가
3Juhwan Mar 31, 2024
f69bc9b
refactor: 명령어로 입력된 position 검증 로직을 커맨드 내부로 이동
3Juhwan Mar 31, 2024
4c9b025
feat: 기존 게임에 방 기능 추가
3Juhwan Mar 31, 2024
c92d719
chore: 기보 샘플 추가
3Juhwan Mar 31, 2024
d367afd
refactor: DAO 인터페이스 분리, 메서드명 수정, service 패키지 분리
3Juhwan Mar 31, 2024
ad6cd59
remove: DAO 테스트 삭제
3Juhwan Mar 31, 2024
75f0647
refactor: 체스 게임과 게임방 패키지 분리, 커맨드 분리
3Juhwan Mar 31, 2024
30c0fe7
fix: DB에 존재하지 않는 데이터를 조회하면 발생하는 예외 처리
3Juhwan Mar 31, 2024
50e75dc
refactor: 게임방 컨트롤러에서 뷰 로직 분리
3Juhwan Mar 31, 2024
7423703
refactor: application에 존재하는 로직을 MainController로 분리
3Juhwan Mar 31, 2024
76752dd
fix: 잘못된 방번호 입력 예외 처리
3Juhwan Mar 31, 2024
23f4260
refactor: 모든 출력 뒤에 개행 추가
3Juhwan Mar 31, 2024
9f6b2e1
refactor: 불필요한 파라미터 제거
3Juhwan Mar 31, 2024
ed7c33b
refactor: var 제거
3Juhwan Mar 31, 2024
153a5a1
refactor: Controller의 비즈니스 로직을 Service로 이전
3Juhwan Apr 1, 2024
8cce027
refactor: Postion에 불필요한 생성자 제거
3Juhwan Apr 1, 2024
928da16
refactor: service 단에 불필요한 생성자 삭제, 내부 필드를 위부에서 주입 받도록 변경
3Juhwan Apr 1, 2024
072b052
chore: 패키지 이동
3Juhwan Apr 1, 2024
f5e3c6f
refactor: 메서드명 수정
3Juhwan Apr 1, 2024
909e885
feat: 사용자 관련 Controller, View 로직 추가
3Juhwan Apr 1, 2024
f22f92e
feat: 사용자 관련 Service, Dao 로직 추가
3Juhwan Apr 1, 2024
0899b82
feat: Room 로직에 사용자 관련 로직 추가
3Juhwan Apr 1, 2024
7b1be6f
refactor: 인터페이스 내 final 삭제
3Juhwan Apr 1, 2024
b1816b2
fix: GameRoomService 테스트 수정
3Juhwan Apr 1, 2024
f7cb258
refactor: final 키워드 삭제, 불필요한 생성자 삭제
3Juhwan Apr 2, 2024
2871ed4
fix: 공백이 입력되면 null이 발생하는 오류 수정
3Juhwan Apr 2, 2024
8769708
docs: 추가 기능2와 관련된 사항 추가
3Juhwan Apr 3, 2024
e36ef5c
refactor: Command 인터페이스명 수정
3Juhwan Apr 3, 2024
c885bed
refactor: 불필요한 괄호, 개행 삭제, final 키워드 추가
3Juhwan Apr 3, 2024
f21dd5b
refactor: roomId 관련 변수명과 쿼리 수정
3Juhwan Apr 3, 2024
5e09e53
refactor: 디미터 법칙에 따라 수정, 컨트롤러 메서드명 수정
3Juhwan Apr 3, 2024
172b453
refactor: isEmpty() 메서드 적용
3Juhwan Apr 3, 2024
2ba8f3f
refactor: 개행 수정
3Juhwan Apr 3, 2024
0fa658a
fix: 무한 반복되는 어플리케이션 개선
3Juhwan Apr 3, 2024
b62df02
refactor: 함수형 인터페이스로 분리
3Juhwan Apr 4, 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
164 changes: 161 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,165 @@
# java-chess

체스 미션 저장소
## Step1, 2 기능 요구사항

## 우아한테크코스 코드리뷰
### 기물 공통

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
- [x] 움직이지 않을 경우 예외가 발생한다.

### Pawn

- [x] 앞에 다른 기물이 없을 때 한 칸 이동한다.
- [x] **[예외]** 앞에 다른 기물이 있을 때
- [x] **[예외]** 두 칸 이상 이동할 때
- [x] 처음 위치일 때 앞으로 두 칸 이동할 수 있다.
- [x] **[예외]** 앞에 다른 기물이 있을 때 (아군, 적군)
- [x] **[예외]** 처음 위치가 아닐 때
- 블랙 : 7 rank
- 화이트 : 2 rank
- [x] 대각선에 상대 기물이 있으면 대각선으로 이동한다.
- [x] **[예외]** 대각선에 상대 기물이 없을 때
- [x] **[예외]** 두 칸 이상 이동할 때
- [x] 뒤로 이동할 수 없다.

### Knight

- [x] L자로 이동한다.
- [x] **[예외]** L자로 이동하지 않을 때
- [x] 이동 경로에 다른 기물이 있어도 뛰어 넘을 수 있다.
- [x] 도착지에 상대 기물이 있으면 잡을 수 있다.
- [x] **[예외]** 도착지에 아군 기물이 있을 때

### Bishop

- [x] 대각선으로 이동할 수 있다.
- [x] **[예외]** 대각선으로 이동하지 않을 때
- [x] 이동 경로에 다른 기물이 있으면 이동할 수 없다.
- [x] 도착지에 상대 기물이 있으면 잡을 수 있다.
- [x] **[예외]** 도착지에 아군 기물이 있을 때

### Rook

- [x] 수직, 수평으로 이동할 수 있다.
- [x] **[예외]** 수직, 수평으로 이동하지 않을 때
- [x] 이동 경로에 다른 기물이 있으면 이동할 수 없다.
- [x] 도착지에 상대 기물이 있으면 잡을 수 있다.
- [x] **[예외]** 도착지에 아군 기물이 있을 때

### Queen

- [x] 수평, 수직, 대각선으로 이동할 수 있다.
- [x] **[예외]** 수평, 수직, 대각선으로 이동하지 않을 때
- [x] 이동 경로에 다른 기물이 있으면 이동할 수 없다.
- [x] 도착지에 상대 기물이 있으면 잡을 수 있다.
- [x] **[예외]** 도착지에 아군 기물이 있을 때

### King

- [x] 수평, 수직, 대각선으로 한 칸 이동할 수 있다.
- [x] **[예외]** 수평, 수직, 대각선으로 이동하지 않을 때
- [x] **[예외]** 두 칸 이상 이동할 때
- [x] 도착지에 상대 기물이 있으면 잡을 수 있다.
- [x] **[예외]** 도착지에 아군 기물이 있을 때

### 체스판

- [x] 포지션이 체스판 범위 내인지 확인한다.
- [x] **[예외]** 범위를 벗어났을 때
- [x] 기물의 이동 경로에 다른 기물이 있는지 확인한다.
- [x] **[예외]** 경로에 다른 기물이 있을 때
- [x] 자신의 턴인지 확인한다.
- [x] **[예외]** 상대의 턴일 때
- [x] 기물을 이동한다.

### 체스판 팩토리

- [x] 기물을 생성한다.
- [x] 체스판을 생성한다.

### 커맨드

- [x] start는 게임을 시작한다.
- [x] end는 게임을 종료한다.
- [x] move는 기물을 이동한다.

### 입력

- [x] 커맨드를 입력받는다.

### 출력

- [x] 체스판을 출력한다.
- [x] 아래(백, 소문자), 위(흑, 대문자)

### 추가 룰

- [ ] 프로모션 : 폰이 상대 마지막 진영까지 도달하면 다른 기물로 변경할 수 있다.
- [ ] 앙파상
- [ ] 캐슬링

## Step3, 4 기능 요구사항

### 체스 게임

- 게임이 시작될 때 체스판을 만든다.
- DB에 저장된 데이터가 존재하면 불러온다.
- DB에 저장된 데이터가 없으면 체스판을 새로 만든다.
- 체스 게임을 진행한다.
- 게임 점수를 계산한다.
- 게임을 종료하면 데이터를 갱신한다.
- 킹이 죽지 않았으면 현재 체스판 데이터를 모두 저장한다.
- 킹이 죽으면 모든 테이터를 삭제한다.


### 점수 계산

- [x] 현재까지 남아 있는 말에 따라 점수를 계산한다.
- [x] 각 팀의 점수를 따로 계산한다.
- [x] queen은 9점, rook은 5점, bishop은 3점, knight는 2.5점이다.
- [x] pawn의 기본 점수는 1점이다.
- [x] 같은 세로줄에 같은 색의 폰이 있는 경우 0.5점을 준다.
- [x] 킹이 없다면 0점이다.

### 커맨드

- start
- [x] 체스판을 출력한다.
- move
- [x] 말을 움직인다.
- [x] 체스판을 출력한다.
- status
- [x] 각 팀의 점수를 출력한다.
- end
- [x] 게임을 종료한다.
- [x] 각 팀의 점수를 출력한다.
- (추가) 킹이 죽으면 게임은 자동으로 종료된다.

### DB CRUD 기능

- [x] 기존 게임 데이터가 존재하는지 여부 조회
- [x] 기존 게임 데이터를 불러오기
- [x] 게임 데이터 갱신 (피스들, 턴)
- [x] 이전 게임 데이터 삭제
- [x] 현재 게임 데이터 저장

### 추가 기능 1: 체스 게임방을 만들고 체스 게임방에 입장할 수 있는 기능을 추가한다.

- [x] 존재하는 모든 게임방 번호를 조회한다.
- [x] 종료된 게임은 제외한다.
- [x] 입장할 게임방 번호를 입력 받는다.
- [x] new를 입력하면 새로운 방을 생성한다.
- **[예외]** 종료된 게임방 번호
- **[예외]** 존재하지 않는 게임방 번호
- [x] 게임을 생성한다. (턴, 피스들)
- [x] 기존 데이터를 불러오기
- [x] 새로 생성하기
- [x] end를 입력하면 게임 데이터를 저장한다.

### 추가 기능 2: 사용자별로 체스 게임 기록을 관리할 수 있다.

- [x] 사용자 이름을 입력 받는다.
- **[예외]** 사용자 이름은 4~10자 사이여야 한다.
- [x] DB에서 사용자 정보를 불러온다.
- [x] 존재하지 않는 사용자라면 새로 추가한다.
- [x] 사용자의 게임 기록을 불러온다.
- 이후는 기존 어플리케이션 흐름대로 진행
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ 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
32 changes: 32 additions & 0 deletions docker/db/mysql/init/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
create table users
(
username varchar(16),
primary key (username)
);

create table rooms
(
user varchar(16),
room_id int,
primary key (room_id),
foreign key (user) references users (username)
);

create table game_states
(
game_id int,
state varchar(8) not null,
primary key (game_id),
foreign key (game_id) references rooms (room_id)
);

create table pieces
(
game_id int,
board_file varchar(1) not null,
board_rank varchar(1) not null,
color varchar(8) not null,
type varchar(8) not null,
primary key (game_id, board_file, board_rank),
foreign key (game_id) references rooms (room_id)
);
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
Empty file removed src/main/java/.gitkeep
Empty file.
8 changes: 8 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import controller.MainController;

public class Application {
public static void main(String[] args) {
MainController mainController = new MainController();
mainController.run();
}
}
32 changes: 32 additions & 0 deletions src/main/java/controller/MainController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package controller;

import controller.game.ChessGameController;
import controller.room.GameRoomController;
import controller.user.UserController;
import database.dao.GameStateDaoImpl;
import database.dao.PieceDaoImpl;
import database.dao.RoomDaoImpl;
import database.dao.UserDaoImpl;
import dto.RoomDto;
import dto.UserDto;
import service.ChessGameService;
import service.GameRoomService;
import service.UserService;

public class MainController {
private final GameRoomController gameRoomController = new GameRoomController(new GameRoomService(new RoomDaoImpl()));
private final ChessGameController chessGameController
= new ChessGameController(
new ChessGameService(
new PieceDaoImpl(),
new GameStateDaoImpl()
)
);
private final UserController userController = new UserController(new UserService(new UserDaoImpl()));

public void run() {
UserDto user = userController.loadUser();
RoomDto room = gameRoomController.loadRoom(user);
chessGameController.run(room);
}
}
35 changes: 35 additions & 0 deletions src/main/java/controller/game/ChessGameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package controller.game;

import controller.game.command.GameCommand;
import domain.ChessGame;
import dto.RoomDto;
import service.ChessGameService;
import view.InputView;
import view.OutputView;

public class ChessGameController {
private final ChessGameService chessGameService;

public ChessGameController(ChessGameService chessGameService) {
this.chessGameService = chessGameService;
}

public void run(RoomDto roomDto) {
ChessGame chessGame = chessGameService.initializeChessGame(roomDto);
OutputView.printGameGuideMessage();
while (chessGame.isPlaying()) {
readCommandUntilValid(chessGame);
}
chessGameService.saveChessGame(chessGame, roomDto);
}

private void readCommandUntilValid(ChessGame chessGame) {
try {
GameCommand command = InputView.readGameCommand();
command.execute(chessGame);
} catch (Exception e) {
OutputView.printErrorMessage(e);
readCommandUntilValid(chessGame);
}
}
}
22 changes: 22 additions & 0 deletions src/main/java/controller/game/command/EndOnGameCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package controller.game.command;

import domain.ChessGame;

import java.util.List;

public class EndOnGameCommand implements GameCommand {
public EndOnGameCommand(final List<String> arguments) {
validateArgumentSize(arguments);
}

private void validateArgumentSize(final List<String> arguments) {
if (!arguments.isEmpty()) {
throw new IllegalArgumentException();
}
}

@Override
public void execute(final ChessGame game) {
game.end();
}
}
7 changes: 7 additions & 0 deletions src/main/java/controller/game/command/GameCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package controller.game.command;

import domain.ChessGame;

public interface GameCommand {
void execute(ChessGame game);
}
52 changes: 52 additions & 0 deletions src/main/java/controller/game/command/MoveOnGameCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package controller.game.command;

import domain.ChessGame;
import domain.board.Score;
import domain.position.Position;
import view.OutputView;

import java.util.List;
import java.util.regex.Pattern;

public class MoveOnGameCommand implements GameCommand {
private static final Pattern POSITION_INPUT_PATTERN = Pattern.compile("^[A-H][1-8]$");
private static final int ARGUMENT_SIZE = 2;

private final Position source;
private final Position target;

public MoveOnGameCommand(final List<String> arguments) {
validateArgumentSize(arguments);
this.source = new Position(arguments.get(0));
this.target = new Position(arguments.get(1));
}

private void validateArgumentSize(final List<String> arguments) {
if (arguments.size() != ARGUMENT_SIZE) {
throw new IllegalArgumentException();
}
validatePositions(arguments);
}

private void validatePositions(final List<String> inputs) {
inputs.forEach(this::validatePositionFormat);
}

private void validatePositionFormat(final String positionInput) {
if (!POSITION_INPUT_PATTERN.matcher(positionInput).matches()) {
throw new IllegalArgumentException();
}
}

@Override
public void execute(final ChessGame game) {
game.move(source, target);
OutputView.printBoard(game.getBoard());

if (game.isGameOver()) {
final Score score = game.getScore();
OutputView.printScore(score);
OutputView.printWinner(score);
}
}
}
Loading