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

오잉또잉 체스게임 #6

Open
wants to merge 61 commits into
base: hanueleee
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
ff4f19d
feat: remove web dependency
woowahan-neo Mar 13, 2023
1bab9ff
feat: add example for functional programming api example
woowahan-neo Mar 13, 2023
98598c0
chore: change package
woowahan-neo Mar 13, 2023
abee5c9
feat: Database 연결
echo724 Mar 14, 2023
4bbccbe
docs: 기능목록 작성
echo724 Mar 14, 2023
644808c
docs: 기능목록 수정
echo724 Mar 14, 2023
29390c8
feat: Position 구현
echo724 Mar 14, 2023
80458aa
feat: Position 검증 기능 추가
echo724 Mar 14, 2023
d902919
feat: Piece 추상 클래스 구현
echo724 Mar 15, 2023
fa15be0
feat: Piece 상속하는 King,Queen,Rook,Knight,Bishop,Pawn 추가
echo724 Mar 15, 2023
2e1eca1
feat: PieceFactory 기능 구현
echo724 Mar 15, 2023
14a6733
feat: Board 생성 구현
echo724 Mar 15, 2023
edaa59a
feat: Board 초기화 구현
echo724 Mar 15, 2023
f482756
refactor: 패키지 이동
echo724 Mar 15, 2023
467627d
feat: InputView 구현
echo724 Mar 15, 2023
c7a7db4
feat: CommandLine 구현
echo724 Mar 15, 2023
232fe0a
fix: Board 초기화 오류 해결
echo724 Mar 15, 2023
cc72eb0
feat: Board에 Piece리스트를 반환하는 메서드 구현
echo724 Mar 15, 2023
c3f340b
feat: Piece에 타입 필드 추가
echo724 Mar 15, 2023
e79765c
feat: ChessGame 구현
echo724 Mar 15, 2023
31c776d
feat: PieceMapper 구현
echo724 Mar 15, 2023
34b9b80
feat: BoardDto 구현
echo724 Mar 15, 2023
a5f3e86
feat: 체스보드 출력 구현
echo724 Mar 15, 2023
d174cd9
feat: ChessController 구현
echo724 Mar 15, 2023
8dae288
feat: Application 구현
echo724 Mar 15, 2023
83915ae
feat: 해당 좌표의 피스를 구하는 기능 구현
echo724 Mar 16, 2023
f6e8145
feat: 좌표에서 또다른 좌표로 방향 구하는 로직 구현
echo724 Mar 16, 2023
6d814c7
feat: 좌표에서 방향 더하는 연산 추가
echo724 Mar 16, 2023
a256899
feat: 이동 경로 상에 다른 피스가 있는지 확인하는 기능 구현
echo724 Mar 16, 2023
03d5ca7
feat(Board): 목적지에 같은 색깔 피스가 있는지 확인하는 기능 구현
echo724 Mar 16, 2023
4c810b1
feat(Board): 피스 위치 이동 기능 구현
echo724 Mar 16, 2023
0acc0ba
mission: 미션1 구현
echo724 Mar 17, 2023
cfd6765
mission: 미션2 구현
echo724 Mar 17, 2023
0ad7f2f
mission: 미션3 구현
echo724 Mar 17, 2023
5ce5dc3
feat: 보드에서 말 이동 검증 구현
echo724 Mar 17, 2023
b6a8808
feat(Piece): 피스들 구현
echo724 Mar 17, 2023
053604f
feat(Position): 거리 계산하는 로직 구현
echo724 Mar 17, 2023
7c9622e
feat(Game): 검증 후 이동하는 로직 구현
echo724 Mar 17, 2023
4cd77f2
feat(GameStatus): 게임 상태 관리 기능 구현
echo724 Mar 17, 2023
fc66c75
feat: 게임 전체 로직 조합
echo724 Mar 17, 2023
a869608
style(View): 출력 문구 수정
echo724 Mar 17, 2023
e83eb59
refactor(BoardDto): 게임 대신 보드를 주입하는 방식으로 수정
echo724 Mar 17, 2023
31e0fe7
feat(OutputView): 에러 메세지 출력 기능 구현
echo724 Mar 17, 2023
a0bc8fe
refactor(Controller): 메서드 정리 및 게임 턴 책임 분리
echo724 Mar 17, 2023
c6f5f35
refactor(EmptyPiece): 빈 피스 실행 예외 처리
echo724 Mar 17, 2023
df8cd7a
refactor: 코드 정리
echo724 Mar 17, 2023
ecfc8b6
refactor(Board): 보드 리펙토링
echo724 Mar 17, 2023
d6a8ff7
refactor(Game): 게임 리펙토링
echo724 Mar 17, 2023
8f8d542
refactor: this 제거
hanueleee Mar 20, 2023
d7d310e
refactor(PieceMapper): if 대신 Map을 사용하여 분기 줄이기
hanueleee Mar 20, 2023
2e37b07
refactor(Piece): 모든 Piece 상속 클래스들의 생성자 로직을 정적 팩토리 메서드 내부로 이동(생성자 단순화)
hanueleee Mar 20, 2023
22384af
refactor(Position): 위치 간의 방향을 계산하는 로직 수정
hanueleee Mar 20, 2023
dfe166c
refactor: 에러 메시지 상수 해제
hanueleee Mar 20, 2023
14ddc61
refactor(dto): BoardDto의 책임을 RankDto와 분배
hanueleee Mar 20, 2023
1b6daee
refactor(view): 시작 메시지를 각각 단일 상수화
hanueleee Mar 20, 2023
c7612a3
refactor: 패키지 정리
hanueleee Mar 20, 2023
bec77c8
test: PieceMapper 테스트
hanueleee Mar 20, 2023
6481479
refactor(Board): getPiecesAt -> findAllByRank 메소드명 수정 및 stream 제거
hanueleee Mar 21, 2023
d0f7612
refactor(ChessController): 정확한 예외클래스 지정
hanueleee Mar 21, 2023
2ba065c
refactor(Color): static메소드 해제
hanueleee Mar 21, 2023
7e54715
refactor: 메소드 순서 정리, 코드 중복 제거
hanueleee Mar 21, 2023
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
61 changes: 58 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,62 @@
# java-chess

Choose a reason for hiding this comment

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

와 commit 보고 벌써 4단계 DB연결 다한줄 ㄷㄷ

Copy link
Author

Choose a reason for hiding this comment

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

킥 킥 어림도 없지


체스 미션 저장소
# 기능 목록

## 우아한테크코스 코드리뷰
## 도메인

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
### 좌표

- [x] 좌표는 file과 rank를 필드로 가진다.
- [x] 좌표는 (A,1) ~ (H,8) 까지 가능
- [x] 좌표는 다른 좌표로의 방향을 구할 수 있다.

### 피스

- [x] 자신의 진영을 필드로 가지고 있다.
- [x] 움직일 수 있는지 검증
- [x] 폰
- [x] 나이트
- [x] 룩
- [x] 비숍
- [x] 퀸
- [x] 킹

Choose a reason for hiding this comment

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

좀 구체적으로 적어주세요

Copy link
Author

Choose a reason for hiding this comment

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

왜여 >< 다 알자나


### 체스판

- [x] 빈 보드를 생성
- [x] 좌표를 입력으로 주었을때, 좌표의 피스를 반환(getPiece)
- [x] 좌표에 피스가 존재하는지 확인
- [x] 같은 색깔 피스 인지 확인.

Choose a reason for hiding this comment

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

확인.

- [x] 피스를 교체(replace)
- [x] 두 좌표를 주었을때, 두 좌표 사이에 피스가 있는지 검증(checkBetweenRoute)
- [x] 목적지에 같은 색깔의 피스가 있는지 확인(checkSameColor)
- [x] 폰이 움직일 수 있는지 확인(checkRestrictionForPawn)
- [x] 대각선으로 움직일때, 상대편 피스가 있는지 확인
- [x] 위,아래 방향으로 움직일때, 칸이 비어있지 않은지 확인

### 피스 팩토리

- [x] 색상에 따라 초기 피스들의 리스트를 반환

### 랭크 : 가로줄을 나타내는 enum

### 파일 : 세로줄을 나타내는 enum

### 게임

- [x] 체스판을 초기화
- [x] 피스를 이동

### 명령

- [x] 입력받은 명령를 검증(start,end,move)

## UI

### 입력

- [x] 명령어를 입력

### 출력

- [x] 체스판을 출력
4 changes: 1 addition & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ repositories {
}

dependencies {
implementation 'com.sparkjava:spark-core:2.9.3'
implementation 'com.sparkjava:spark-template-handlebars:2.7.1'
implementation 'ch.qos.logback:logback-classic:1.2.10'
testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
runtimeOnly 'mysql:mysql-connector-java:8.0.28'
}

java {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/chess/Applictaion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package chess;

import chess.controller.ChessController;

public class Applictaion {

public static void main(String[] args) {
ChessController chessController = new ChessController();
chessController.execute();
}
}
22 changes: 0 additions & 22 deletions src/main/java/chess/WebApplication.java

This file was deleted.

48 changes: 48 additions & 0 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package chess.controller;

import chess.controller.dto.BoardDto;
import chess.domain.ChessGame;
import chess.domain.CommandLine;
import chess.view.InputView;
import chess.view.OutputView;
import java.util.NoSuchElementException;

public class ChessController {

public ChessController() {
}

public void execute() {
OutputView.printGameStartMessage();
ChessGame chessGame = new ChessGame();
while (!chessGame.isGameEnd()) {
runGame(chessGame);
}
}

private void runGame(final ChessGame chessGame) {
try {
CommandLine commandLine = getCommandLine();
handleCommandLine(chessGame, commandLine);
OutputView.printBoard(BoardDto.create(chessGame.getBoard()));
} catch (IllegalArgumentException | IllegalStateException | NoSuchElementException e) {
OutputView.printError(e.getMessage());
}
}

private CommandLine getCommandLine() {
return new CommandLine(InputView.readCommand());
}

private void handleCommandLine(final ChessGame chessGame, final CommandLine commandLine) {
if (commandLine.isStart()) {
chessGame.start();
}
if (commandLine.isMove()) {
chessGame.move(commandLine.getArguments());
}
if (commandLine.isEnd()) {
chessGame.end();
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/chess/controller/dto/BoardDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package chess.controller.dto;

import chess.domain.Board;
import chess.domain.position.Rank;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BoardDto {

private final List<RankDto> ranks;

private BoardDto(List<RankDto> ranks) {
this.ranks = ranks;
}

public static BoardDto create(Board board) {
List<RankDto> rankDtos = new ArrayList<>();
for (Rank rank : Rank.values()) {
RankDto rankDto = RankDto.create(board.findAllByRank(rank));
rankDtos.add(rankDto);
}
Collections.reverse(rankDtos);
return new BoardDto(rankDtos);
}

public List<RankDto> getRanks() {
return this.ranks;
}
}
24 changes: 24 additions & 0 deletions src/main/java/chess/controller/dto/PieceMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package chess.controller.dto;

import chess.domain.piece.Piece;
import chess.domain.piece.PieceType;
import java.util.Map;

public class PieceMapper {
private static final Map<PieceType, String> mapper = Map.of(
PieceType.EMPTY, ".",
PieceType.PAWN, "p",
PieceType.BISHOP, "b",
PieceType.KNIGHT, "n",
PieceType.ROOK, "r",
PieceType.QUEEN, "q",
PieceType.KING, "k"
);

public static String map(Piece piece) {
if (!piece.isWhite()) {
return mapper.get(piece.getType()).toUpperCase();
}
return mapper.get(piece.getType());
}
}
25 changes: 25 additions & 0 deletions src/main/java/chess/controller/dto/RankDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package chess.controller.dto;

import chess.domain.piece.Piece;
import java.util.List;

public class RankDto {

private final String stringRank;

private RankDto(String stringRank) {
this.stringRank = stringRank;
}

public static RankDto create(List<Piece> pieces) {
StringBuilder builder = new StringBuilder();
for (Piece piece : pieces) {
builder.append(PieceMapper.map(piece));
}
return new RankDto(builder.toString());
}

public String getStringRank() {
return stringRank;
}
}
128 changes: 128 additions & 0 deletions src/main/java/chess/domain/Board.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package chess.domain;

import chess.domain.piece.Color;
import chess.domain.piece.Empty;
import chess.domain.piece.Piece;
import chess.domain.piece.PieceFactory;
import chess.domain.position.Direction;
import chess.domain.position.File;
import chess.domain.position.Position;
import chess.domain.position.Rank;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Board {

public static final int WHITE_GENERALS_RANK = 0;
public static final int WHITE_PAWNS_RANK = 1;
public static final int BLACK_PAWNS_RANK = 6;
public static final int BLACK_GENERALS_RANK = 7;

private final Map<Position, Piece> board;

private Board(final Map<Position, Piece> board) {
this.board = board;
}

public static Board create() {
Map<Position, Piece> board = new TreeMap<>();
for (File file : File.values()) {
for (Rank rank : Rank.values()) {

Choose a reason for hiding this comment

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

인덴트 2 신경 안쓰나..?ㅎ

Copy link
Author

Choose a reason for hiding this comment

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

(스터디때 하입보이가 했던 말처럼) 난 얘는 depth 줄이겠다고 뭔가 하는게 더 가독성 떨어지고 별로라고 생각 ><
flatmap을 쓸 수도 있겠지만, 개인적으로 flatmap 가독성 최악이라고 생각ㅎㅎ

Position position = Position.from(file, rank);
board.put(position, Empty.create());
}
}
return new Board(board);
}

public void initialize() {
List<Piece> whiteGenerals = PieceFactory.createWhiteGenerals();
List<Piece> whitePawns = PieceFactory.createWhitePawns();
List<Piece> blackPawns = PieceFactory.createBlackPawns();
List<Piece> blackGenerals = PieceFactory.createBlackGenerals();
for (Position position : board.keySet()) {
placePieceAtPosition(whiteGenerals, position, WHITE_GENERALS_RANK);
placePieceAtPosition(whitePawns, position, WHITE_PAWNS_RANK);
placePieceAtPosition(blackPawns, position, BLACK_PAWNS_RANK);
placePieceAtPosition(blackGenerals, position, BLACK_GENERALS_RANK);
}
}

private void placePieceAtPosition(final List<Piece> pieces, final Position position, int rank) {
if (position.isRank(rank)) {
board.put(position, pieces.get(position.getFile().getIndex()));
}
}

public Piece getValidSourcePiece(final Position source, final Color color) {
if (isEmpty(source)) {
throw new IllegalArgumentException("피스가 존재하지 않습니다.");
}
if (!isSameColor(source, color)) {
throw new IllegalArgumentException("상대편 피스입니다.");
}
return board.get(source);
}

public void checkBetweenRoute(final Position source, final Position destination) {
Direction direction = source.calculateDirection(destination);
Position move = source.addDirection(direction);
while (!destination.equals(move)) {
checkOtherPieceInRoute(move);
move = move.addDirection(direction);
}
}

private void checkOtherPieceInRoute(final Position move) {
if (!isEmpty(move)) {
throw new IllegalArgumentException("경로에 다른 피스가 존재합니다.");
}
}

public void checkRestrictionForPawn(final Position source, final Position destination, final Color color) {

Choose a reason for hiding this comment

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

어떻게 보면 Pawn의 개인사정인데,
이걸 Board에서 하는 것은 객체간 역할 분리가 잘 안 이루어진 것 같다고 생각함!
Pawn의 개인사는 Pawn 안에서 검증하는게 더 좋을 것 같아

Direction direction = source.calculateDirection(destination);
if (direction == Direction.N || direction == Direction.S) {
checkOtherPieceInRoute(destination);
}
if (Direction.isDiagonal(direction)) {
checkDiagonalPiece(destination);
checkSameColor(destination, color);
}
}

private void checkDiagonalPiece(final Position destination) {

Choose a reason for hiding this comment

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

왜 diagonal 체크인데 isEmpty를 하는거야?

Copy link
Author

Choose a reason for hiding this comment

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

폰은 대각선이 비어있으면 (다른 말을 잡을 수 없으면) 대각선으로 이동할 수 없으니까

if (isEmpty(destination)) {
throw new IllegalArgumentException("비어있기 때문에 대각선으로 이동할 수 없습니다.");
}
}

public void checkSameColor(final Position destination, Color color) {
if (isSameColor(destination, color)) {
throw new IllegalArgumentException("목적지에 같은 색깔의 피스가 있습니다.");
}
}

public void replace(final Position source, final Position destination) {
board.put(destination, board.get(source));
board.put(source, Empty.create());
}

private boolean isEmpty(final Position position) {
return board.get(position).isEmpty();
}

private boolean isSameColor(final Position position, final Color color) {
return board.get(position).isSameColor(color);
}

public List<Piece> findAllByRank(Rank rank) {
List<Piece> result = new ArrayList<>();
for (File file : File.values()) {
Position position = Position.from(file, rank);
result.add(board.get(position));
}
return result;
}
}
Loading