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

Feat/level1 #1

Merged
merged 44 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
33c122b
docs: 기능구현 목록 작성
kimtaesoo99 Jun 29, 2023
ac07697
feat: 기물의 공통 속성을 가지는 추상 클래스 추가
kimtaesoo99 Jun 29, 2023
a45f16c
feat: 기물의 구현체 비숍 추가
kimtaesoo99 Jun 29, 2023
bd7c2d4
feat: 기물의 구현체 킹 추가
kimtaesoo99 Jun 29, 2023
20a79ca
feat: 기물의 나이트 추가
kimtaesoo99 Jun 29, 2023
5aa94a5
feat: 기물의 구현체 폰 추가
kimtaesoo99 Jun 29, 2023
afa3851
feat: 기물의 구현체 퀸 추가
kimtaesoo99 Jun 29, 2023
3a92fc8
feat: 기물의 구현체 룩 추가
kimtaesoo99 Jun 29, 2023
61bb2ef
feat: Location을 컬럼을 나타내는 File 추가
kimtaesoo99 Jun 29, 2023
5c82e6f
feat: Location을 로우를 나타내는 Rank 추가
kimtaesoo99 Jun 29, 2023
3d06229
feat: 기물의 이름과 팀을 나타내는 State 추가
kimtaesoo99 Jun 29, 2023
d03e694
feat: rank, file을 가지는 Location 추가
kimtaesoo99 Jun 29, 2023
6967868
feat: 체스판을 초기화해주는 initBoard 추가
kimtaesoo99 Jun 29, 2023
1806ee9
feat: 방향을 나타내는 Direction 추가
kimtaesoo99 Jun 29, 2023
177a4cb
feat: 입력을 관리하는 Command 추가
kimtaesoo99 Jun 29, 2023
5741b32
feat: Location을 키로 Pieces를 벨류로 하는 맵을 관리하는 일급컬렉션 Board 추가
kimtaesoo99 Jun 29, 2023
96fdbe2
feat: 출력을 담당하는 OutputView추가
kimtaesoo99 Jun 29, 2023
e25119a
feat: 입력을 담당하는 InputView추가
kimtaesoo99 Jun 29, 2023
f65812f
feat: 입력의 검증을 위한 InputValidation추가
kimtaesoo99 Jun 29, 2023
b1bf8be
feat: 예외 메시지를 담당하는 Error 추가
kimtaesoo99 Jun 29, 2023
ef911de
feat: 전체적인 흐름을 담당하는 컨트롤러 추가
kimtaesoo99 Jun 29, 2023
55ad847
feat: 시작을 알리는 Main 추가
kimtaesoo99 Jun 29, 2023
1461e0c
test: 기물 테스트 추가
kimtaesoo99 Jun 29, 2023
3245948
feat: 체스판의 상태를 보내주는 DTO 추가
kimtaesoo99 Jun 29, 2023
2ba5b9a
test: 상태를 표현하는 테스트 추가
kimtaesoo99 Jun 29, 2023
bd5fb4d
test: 체스판을 초기화 테스트 추가
kimtaesoo99 Jun 29, 2023
b9c73b3
chore: 설정 추가
kimtaesoo99 Jun 29, 2023
fa6c6b8
test: 체스판 테스트 추가
kimtaesoo99 Jun 29, 2023
cbd5ad0
refactor: public 메서드로 설정하였습니다.
kimtaesoo99 Jul 1, 2023
5087472
refactor: 출력을 위한 로직을 DTO에 위임하였습니다.
kimtaesoo99 Jul 1, 2023
eff0320
refactor: 패키징이동 및 출력시 보여지는 로직 추가
kimtaesoo99 Jul 1, 2023
f3f146a
refactor: 패키징이동 및 백,흑 순서를 보장하도록 수정
kimtaesoo99 Jul 1, 2023
2a6aa29
refactor: 패키징이동 및 개행적용
kimtaesoo99 Jul 1, 2023
d750454
refactor: 예외 추가및 패키지 이동
kimtaesoo99 Jul 1, 2023
0690c52
refactor: 패키지 이동
kimtaesoo99 Jul 1, 2023
bed7daf
remove: 입력값 검증을 command로 위임
kimtaesoo99 Jul 1, 2023
490ff2e
remove: 패키지 이동 및 로직 단순화
kimtaesoo99 Jul 1, 2023
c6626e6
remove: 패키지 이동 및 public 메서드로 설정
kimtaesoo99 Jul 1, 2023
3c0859b
remove: 패키지 이동 및 로직 단순화
kimtaesoo99 Jul 1, 2023
20f2584
remove: 패키지 이동
kimtaesoo99 Jul 1, 2023
6177d2c
remove: 패키지 이동 및 예외 로직 추가
kimtaesoo99 Jul 1, 2023
932097c
test: 추가적인 예외 처리
kimtaesoo99 Jul 1, 2023
94a3649
feat: 스플릿을 해주는 객체 추가
kimtaesoo99 Jul 1, 2023
cc24b10
test: import 추가
kimtaesoo99 Jul 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 9 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ plugins {
id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
mavenCentral()
}

dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}

test {
useJUnitPlatform()
}
}
2 changes: 0 additions & 2 deletions src/main/java/Main.java

This file was deleted.

39 changes: 39 additions & 0 deletions src/main/java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 체스

- 체스판 위에 알맞은 순서대로 기물을 배치시킴
- 입력에 따라 해당 위치의 기물을 옮김

- 도메인 설계

## 체스판(8x8) 체스칸을 관리하는 일급 컬렉션
- [x] 맵으로 체스칸을 관리
- [x] 정적팩토리 메서드를 사용하여 초기화를 통해 기물을 배치
- [x] 해당 위치의 기물이 이동가능한지
- [x] 입력으로 들어온 위치에 기물이 있는지
- [x] 시작점과 끝점의 기물의 색상이 같은지
- [x] 시작점에서 이동가능한 위치인지
- [x] 이동경로에 기물이 있는지
- [x] 현재 체스판 상황을 반환

## 기물
- [x] 이동할수 있는지
- [x] 해당 말이 검정색인지
- [x] 이름을 반환
- [x] 검은색 기물인지
- [x] 나이트인지
- [x] 폰인지


## 위치 (인스턴스 변수 가로(Rank(, 세로(File)를 가짐 - Rank,File은 체스 용어)
- [x] 같은 위치인지
- [x] 같은 file인지
- [x] 같은 rank인지
- [x] rank 이름을 반환
- [x] file 이름을 반환

## 방향 enum
- [x] 같은 방향인지
- [x] 이동하려는 방향이 어느쪽인지
- [x] 해당 방향이 위또는 아래인지
- [x] row를 반환
- [x] column을 반환
10 changes: 10 additions & 0 deletions src/main/java/chess/Starter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package chess;

import chess.controller.Controller;

public class Starter {
public static void main(String[] args) {
Controller controller = new Controller();
controller.start();
}
}
86 changes: 86 additions & 0 deletions src/main/java/chess/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package chess.controller;

import chess.domain.additional.Command;
import chess.domain.board.Board;
import chess.domain.board.Location;
import chess.domain.board.State;
import chess.dto.BoardStatusResponse;
import chess.service.InitBoard;
import chess.util.Splitter;
import chess.view.InputView;
import chess.view.OutputView;

public class Controller {

private static final int PRE_INDEX = 1;
private static final int MOVE_INDEX = 2;
private static final int RANK_INDEX = 0;
private static final int FILE_INDEX = 1;

private Board board;

public void start() {
OutputView.printStart();
startGame();
}

private void startGame() {
Command command = getStartCommand();
initBoard();
OutputView.printBoardStatus(BoardStatusResponse.from(board));
State turn = State.WHITE_TEAM;

while (!command.isEnd()) {
command = getCommand(turn);
turn = turn.changeTurn();
}
}

private Command getStartCommand() {
try {
String input = InputView.readCommand();
return Command.createStartCommand(input);
} catch (IllegalStateException e) {
OutputView.printErrorMessage(e.getMessage());
return getStartCommand();
}
}

private void initBoard() {
board = new Board(new InitBoard().getInitBoard());
}

private Command getCommand(final State turn) {
try {
String input = InputView.readCommand();
Command command = Command.createCommand(input);
checkMoveCommand(command, input, turn);
return command;
} catch (IllegalStateException e) {
OutputView.printErrorMessage(e.getMessage());
return getCommand(turn);
}
}

private void checkMoveCommand(final Command command, final String input, final State turn) {
if (command.isMove()) {
findMoveLocation(input, turn);
}
}

private void findMoveLocation(final String input, final State turn) {
String preLocation = Splitter.splitString(input, PRE_INDEX);
String moveLocation = Splitter.splitString(input, MOVE_INDEX);

movePieces(preLocation, moveLocation, turn);
}

private void movePieces(final String preLocation, final String moveLocation, final State turn) {
Location pre = Location.from(preLocation.charAt(RANK_INDEX), preLocation.charAt(FILE_INDEX));
Location move = Location.from(moveLocation.charAt(RANK_INDEX), moveLocation.charAt(FILE_INDEX));

board.movePieces(pre, move, turn);

OutputView.printBoardStatus(BoardStatusResponse.from(board));
}
}
100 changes: 100 additions & 0 deletions src/main/java/chess/domain/additional/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package chess.domain.additional;

import java.util.Arrays;

import static chess.domain.additional.Error.CAN_START_WITH_START_COMMAND;
import static chess.domain.additional.Error.EARLY_START_GAME;
import static chess.domain.additional.Error.WRONG_INPUT;
import static chess.domain.additional.Error.WRONG_MOVE_COMMAND;
import static chess.util.Splitter.splitSize;
import static chess.util.Splitter.splitString;
import static chess.util.Splitter.splitStringLength;

public enum Command {

START("start"),
END("end"),
MOVE("move");

private static final int COMMAND = 0;
private static final int CORRECT_MOVE_SIZE = 3;
private static final int PRE_LOCATION_INFO = 1;
private static final int MOVE_LOCATION_INFO = 2;
private static final int MOVE_INFO_LENGTH = 2;
private static final String START_COMMAND = "start";
private static final String END_COMMAND = "end";
private static final String MOVE_COMMAND = "move";

private final String select;

Command(final String select) {
this.select = select;
}

public static Command createStartCommand(final String input) {
validationFirstCommand(input);
return Command.START;
}

public static Command createCommand(final String input) {
validationCommand(input);

if (isMoveCommand(input)) {
validateMoveCommand(input);
return Command.MOVE;
}

return Command.END;
}

private static void validationFirstCommand(final String input) {
if (!isStartCommand(input)) {
throw new IllegalStateException(CAN_START_WITH_START_COMMAND.getMessage());
}
}

private static void validationCommand(final String input) {
if (!isCorrectCommand(input)) {
throw new IllegalStateException(WRONG_INPUT.getMessage());
}

if (isStartCommand(input)) {
throw new IllegalStateException(EARLY_START_GAME.getMessage());
}
}

private static boolean isStartCommand(final String input) {
return Command.START.select.equals(input);
}

private static boolean isCorrectCommand(final String input) {
return Arrays.stream(Command.values())
.anyMatch(command -> splitString(input, COMMAND).equals(command.select));
}

private static boolean isMoveCommand(final String input) {
return input.startsWith(Command.MOVE.select);
}

private static void validateMoveCommand(final String input) {
if (splitSize(input) != CORRECT_MOVE_SIZE) {
throw new IllegalStateException(WRONG_MOVE_COMMAND.getMessage());
}

if (splitStringLength(input, PRE_LOCATION_INFO) != MOVE_INFO_LENGTH || splitStringLength(input, MOVE_LOCATION_INFO) != MOVE_INFO_LENGTH) {
throw new IllegalStateException(WRONG_MOVE_COMMAND.getMessage());
}
}

public boolean isEnd() {
return this.select.equals(END_COMMAND);
}

public boolean isStart() {
return this.select.equals(START_COMMAND);
}

public boolean isMove() {
return this.select.equals(MOVE_COMMAND);
}
}
65 changes: 65 additions & 0 deletions src/main/java/chess/domain/additional/Direction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package chess.domain.additional;

import java.util.Arrays;

import static chess.domain.additional.Error.WRONG_ROW_OR_COLUMN;

public enum Direction {

UP(0, 1),
DOWN(0, -1),
RIGHT(1, 0),
LEFT(-1, 0),
FIRST_DIAGONAL(1, 1),
SECOND_DIAGONAL(1, -1),
THIRD_DIAGONAL(-1, -1),
FOURTH_DIAGONAL(-1, 1),
DOUBLE_UP(0,2),
DOUBLE_DOWN(0,-2),
FIRST_DIAGONAL_UP(1,2),
FIRST_DIAGONAL_RIGHT(2,1),
SECOND_DIAGONAL_RIGHT(2,-1),
SECOND_DIAGONAL_DOWN(1,-2),
THIRD_DIAGONAL_DOWN(-1,-2),
THIRD_DIAGONAL_LEFT(-2,-1),
FOURTH_DIAGONAL_LEFT(-2,1),
FOURTH_DIAGONAL_UP(-1,2);

private static final int ZERO = 0;

private final int row;
private final int column;

Direction(final int row, final int column) {
this.row = row;
this.column = column;
}

private static boolean isSameDirection(final int row, final int column, final Direction direction) {
return direction.row == row && direction.column == column;
}

public static Direction from(final int row, final int column) {
return Arrays.stream(Direction.values())
.filter(direction -> isSameDirection(row, column, direction))
.findAny()
.orElseThrow(() -> new IllegalStateException(WRONG_ROW_OR_COLUMN.getMessage()));
}

public static int getSubtractDirection(final char pre, final char move) {
int gap = move - pre;
return Integer.compare(gap, ZERO);
}

public boolean isUpOrDown() {
return this.equals(UP) || this.equals(DOWN);
}

public int getRow() {
return row;
}

public int getColumn() {
return column;
}
}
29 changes: 29 additions & 0 deletions src/main/java/chess/domain/additional/Error.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package chess.domain.additional;

public enum Error {

WRONG_INPUT("잘못된 입력입니다."),
HAS_NOT_PIECES("해당 위치에는 기물이 없습니다."),
MOVE_LOCATION_IS_SAME_COLOR("이동하려는 위치에는 같은 색깔의 기물이 있습니다."),
CAN_NOT_MOVE_RANGE("기물이 움직일 수 있는 범위가 아닙니다."),
DO_NOT_STAY("제자리로 움직일 수 없습니다."),
PAWN_MOVE_DIAGONALLY_WITH_ENEMY("폰이 대각선으로 움직이려면 적군이 있어야합니다."),
CAN_NOT_MOVE_BECAUSE_OBSTACLE("동선에 기물이 있어서 움직일 수 없습니다."),
WRONG_ROW_OR_COLUMN("잘못된 row와 column입니다."),
WRONG_FILE_NAME("잘못된 File의 이름입니다."),
WRONG_RANK_NAME("잘못된 rank의 이름입니다."),
CAN_START_WITH_START_COMMAND("게임을 시작하려면 start를 입력해주세요"),
EARLY_START_GAME("이미 게임이 진행중입니다."),
WRONG_MOVE_COMMAND("잘못된 이동정보입니다."),
WRONG_TURN("이전에 움직인 기물을 색상과 현재 움직이려는 기물의 색상이 같습니다.");

private final String message;

Error(final String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}