Skip to content

Commit

Permalink
[라빈] 체스 웹/DB 미션 제출합니다 (#133)
Browse files Browse the repository at this point in the history
* doc: 체스 1단계 기능 요구 사항 정리

* feat: 위치 구현

* feat: 가로 축 구현

* feat: 보드판 초기화

* feat: 체스 게임을 시작하는 명령어 입력
refactor: final 키워드 추가

* feat: 이동 전략 구현

* feat: 폰의 이동 전략과 팀별 이동 전략

* feat: 말 이동 시 장애물 탐색
    - 게임을 진행하는 ChessRunner 클래스 구현

* feat: 방향 전략 구현

* feat: 2단계 구현

* feat: 왕이 죽었을 때 승리한 팀 출력

* feat: 왕이 죽었을 때 게임 종료

* feat: status 명령어 입력 시 점수 계산

* feat: 3단계 기능 구현

* doc: README 업데이트

* refactor: 세부 네이밍 수정

* refactor: 방향 전략 생성 분기문 삭제

* refactor: 테스트 코드 디렉토리 추가

* refactor: 테스트 코드 추가

* refactor: 변경되면 안되는 매개 변수, 클래스에 final 키워드 추가

* refactor: 컨트롤러의 실행 메서드를 명령어 별로 분리

* refactor: DirectionStrategy 의 구현 클래스들의 테스트 코드 추가

* refactor: 컨트롤러 추상화

* refactor: 컨트롤러 추상화(2)

* refactor: 1차 수정

* refactor: Dto 추가 / ChessRunner 에서 Dto 에 적합한 값을 넘겨주도록 메서드 수정

* refactor: 게임 종료 경우에 따라 점수 출력 로직 구현 / 객체 null 반환을 Optional 을 이용하도록 변경 / 각 체스 말을 초기화 할때의 정보를 enum 으로 구현

* refactor: 수정한 클래스에 맞게 테스트 코드 추가

* feat: index 페이지 제작

* feat: index 에서 start 를 누르면 game 으로 이동되도록 구현

* feat: 체스판에 말 띄우기

* feat: 보드 위에 말 출력

* feat: 웹에서 상태 출력 / 종료 기능 구현

* refactor: 이동을 못하는 버그 수정

* refactor: 웹에서 이동 기능 구현

* refactor: 에러 로그, 이동 경로 출력 버그 수정

* refactor: 프로그램 실행 시 재귀 로직 제거 / 테스트 메서드를 작은 단위 테스트로 분리 / 승자가 결정되지 않았을 때 던지는 예외 제거

* refactor: 웹에서 점수 출력 시 black, white 둘 다 출력 되도록 변경 / 왕을 잡아서 게임이 끝날 시 종료 페이지로 이동

* refactor: 콘솔에서 status 명령 입력 시 양 팀의 점수 모두 계산해 출력 / 컨벤션 수정 / 상수 추출

* feat: ChessBoard 추가 테스트

* feat: 가장 최근에 추가된 ChessBoard 찾는 기능 추가

* feat: 가장 최근에 추가 된 ChessBoard 삭제 기능 구현

* feat: 피스 정보 추가, 업데이트, 삭제 구현

* feat: 데이터베이스에서 피스 정보 불러오기 - (1)

* feat: db 에서 읽은 값으로 각 피스 초기화

* feat: 현재 팀 정보 데이터베이스에 저장 구현

* feat: 게임 시작 또는 체스 게임 불러오기 기능 구현
refactor: 컨벤션 수정

* feat: 이동 후의 결과 데이터베이스에 업데이트 구현(포지션 이름 매핑 수정필요)

* feat: 이동 후에 정보를 저장해 서버 종료 후에도 게임 진행 가능하게 구현

* feat: end 버튼 누를 시 양 팀의 점수를 계산해서 보여주고 종료 / 한 팀이 다른 팀의 왕을 잡았을 때 데이터 베이스에 정보를 삭제하고 게임 종료

* refactor: 웹의 체스 보드의 각 칸마다 위치 값 표시

* refactor: 불필요한 Piece 정보 수정 메서드 삭제 / 컨벤션 수정 / 테스트 코드에 맞게 데이터 형식 변경

* feat: 플레이어 입력, 게임 방을 위한 뷰 구현

* feat: 플레이어 정보 저장, 검색, 삭제 기능 구현

* feat: 기존의 게임 정보 불러오기 구현

* feat: 게임 목록에서 불러오기 기능 구현(1)

* feat: 게임 목록에서 불러오기 기능 구현(2) - 데이터 불러오기 기능 구현

* feat: 종료 기능 구현
refactor: 디자인 수정

* refactor: DAO 의 코드 수정 / 연결하는 DB 변경

* refactor: Service Layer 추가 / DAO, DTO 패키지 이동

* refactor: DAO 에 try-with-resources 적용

* refactor: service layer 추가

* refactor: controller 에 dao 를 이용하는 역할 제거

* refactor: piece -> pieceOnBoard 모델로 변경

* refactor: 신규 게임 시작 기능 수정

* refactor: controller 의 기능을 Service layer 로 분리

* refactor: Optional 객체의 null 검사 로직 추가

* refactor: 메서드 위치 수정

* refactor: ResultSet, PreparedStatement 닫는 구문 추가

* refactor: 체스 게임 화면에 현재 진행중인 게임 id 출력하게 변경

* refactor: 서비스 내의 상태를 갖는 객체의 생명주기를 메서드 단위로 수정

* refactor: DAO 가 도메인 자료 구조를 사용하도록 변경

* refactor: TileDTO, BoardScoreDTO 의 setter 메서드 삭제

* refactor: SQLException 에 대한 Custom RuntimeException 을 만들어서 예외 페이지 출력

* refactor: findFirst 를 Optional 로 래핑한 부분 수정

Co-authored-by: 김예빈 <[email protected]>
  • Loading branch information
giantim and 김예빈 authored Apr 19, 2020
1 parent 01a6d6c commit 86c76d6
Show file tree
Hide file tree
Showing 83 changed files with 2,382 additions and 129 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
compile('ch.qos.logback:logback-classic:1.2.3')
testCompile('org.junit.jupiter:junit-jupiter:5.6.0')
testCompile('org.assertj:assertj-core:3.15.0')
compile("mysql:mysql-connector-java:8.0.16")
}

test {
Expand Down
19 changes: 5 additions & 14 deletions src/main/java/chess/WebUIChessApplication.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
package chess;

import spark.ModelAndView;
import spark.template.handlebars.HandlebarsTemplateEngine;
import chess.controller.WebChessController;

import java.util.HashMap;
import java.util.Map;

import static spark.Spark.get;
import static spark.Spark.staticFiles;

public class WebUIChessApplication {
public static void main(String[] args) {
get("/", (req, res) -> {
Map<String, Object> model = new HashMap<>();
return render(model, "index.html");
});
}

private static String render(Map<String, Object> model, String templatePath) {
return new HandlebarsTemplateEngine().render(new ModelAndView(model, templatePath));
staticFiles.location("/templates");
WebChessController webChessController = new WebChessController();
webChessController.playChess();
}
}
50 changes: 36 additions & 14 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package chess.controller;

import chess.controller.dto.TeamDto;
import chess.domain.ChessRunner;
import chess.dto.TeamDTO;
import chess.view.ConsoleInputView;
import chess.view.ConsoleOutputView;
import chess.view.InputView;
import chess.view.OutputView;
import org.apache.commons.lang3.StringUtils;

import java.util.Optional;

public class ChessController {
private static InputView inputView = new ConsoleInputView();
private static OutputView outputView = new ConsoleOutputView();

public static void start() {
Command command = getCommand();
outputView.printGameRule();
Command command = getGameCommand();
if (command.isStart()) {
ChessRunner chessRunner = new ChessRunner();
GameController gameController = command.getGameController();
Expand All @@ -23,13 +26,22 @@ public static void start() {
}
}

private static Command getCommand() {
try {
return Command.of(inputView.askChessRun());
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return getCommand();
private static Command getGameCommand() {
Optional<Command> command = Optional.empty();

do {
command = Command.of(inputView.askGameCommand());
} while (isEmptyCommand(command));
return command.get();
}

private static boolean isEmptyCommand(Optional<Command> command) {
if (command.isPresent()) {
return false;
}

System.out.println("잘못된 명령어를 입력하였습니다.");
return true;
}

private static void runChessGame(Command command, ChessRunner chessRunner) {
Expand All @@ -41,19 +53,29 @@ private static void runChessGame(Command command, ChessRunner chessRunner) {

private static Command validateExecute(Command command, ChessRunner chessRunner) {
try {
String commands = inputView.askGameCommand();
command = Command.of(commands);
GameController gameController = command.getGameController();
gameController.execute(chessRunner, commands);
} catch (IllegalArgumentException e) {
command = executeByCommand(command, chessRunner);
} catch (IllegalArgumentException | ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
}
return command;
}

private static Command executeByCommand(Command command, ChessRunner chessRunner) {
String input = inputView.askGameCommand();
Optional<Command> inputCommand = Command.of(input);

while (isEmptyCommand(inputCommand)) {
input = inputView.askGameCommand();
inputCommand = Command.of(input);
}
command = inputCommand.get();
command.execute(chessRunner, input);
return command;
}

private static void printWinner(ChessRunner chessRunner) {
if (chessRunner.isEndChess()) {
TeamDto teamDto = new TeamDto(chessRunner.getWinner());
TeamDTO teamDto = new TeamDTO(chessRunner.getWinner());
outputView.printWinner(teamDto.getTeamName());
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/chess/controller/Command.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package chess.controller;

import chess.domain.ChessRunner;

import java.util.Arrays;
import java.util.Optional;

public enum Command {
START("start", new StartController()),
Expand All @@ -16,11 +19,10 @@ public enum Command {
this.gameController = gameController;
}

public static Command of(final String command) {
public static Optional<Command> of(final String command) {
return Arrays.stream(values())
.filter(c -> command.contains(c.command))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("잘못된 명령어를 입력하였습니다."));
.findFirst();
}

public boolean isStart() {
Expand All @@ -34,4 +36,8 @@ public GameController getGameController() {
public boolean isEnd() {
return this == END;
}

public void execute(ChessRunner chessRunner, String commands) {
this.gameController.execute(chessRunner, commands);
}
}
8 changes: 4 additions & 4 deletions src/main/java/chess/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package chess.controller;

import chess.controller.dto.BoardDto;
import chess.controller.dto.PositionDto;
import chess.domain.ChessRunner;
import chess.domain.position.Position;
import chess.dto.BoardDTO;
import chess.dto.PositionDTO;
import chess.view.ConsoleOutputView;
import chess.view.OutputView;

Expand All @@ -17,8 +17,8 @@ public GameController() {
}

protected void printBoard(final Map<String, String> board) {
BoardDto boardDto = new BoardDto(board);
PositionDto positionDto = new PositionDto(Position.getPositions());
BoardDTO boardDto = new BoardDTO(board);
PositionDTO positionDto = new PositionDTO(Position.getPositions());
this.outputView.printBoard(positionDto.getPositions(), boardDto.get());
}

Expand Down
18 changes: 13 additions & 5 deletions src/main/java/chess/controller/StatusController.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package chess.controller;

import chess.controller.dto.BoardScoreDto;
import chess.controller.dto.TeamDto;
import chess.domain.ChessRunner;
import chess.dto.BoardScoreDTO;

import java.util.List;
import java.util.stream.Collectors;

public class StatusController extends GameController {
private static final String DELIMITER = ": ";
private static final String NEW_LINE = "\n";

public StatusController() {
super();
}

@Override
public void execute(ChessRunner chessRunner, String input) {
BoardScoreDto boardScoreDto = new BoardScoreDto(chessRunner.calculateScore());
TeamDto teamDto = new TeamDto(chessRunner.getCurrentTeam());
outputView.printStatus(boardScoreDto.getBoardScore(), teamDto.getTeamName());
List<BoardScoreDTO> boardScoreDtos = chessRunner.calculateScores();
String scores = boardScoreDtos.stream()
.map(dto -> dto.getTeam() + DELIMITER + dto.getBoardScore())
.collect(Collectors.joining(NEW_LINE));

outputView.printStatus(scores);
printBoard(chessRunner.getBoardEntities());
}
}
181 changes: 181 additions & 0 deletions src/main/java/chess/controller/WebChessController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package chess.controller;

import chess.dao.ChessBoard;
import chess.dao.CustomSQLException;
import chess.dao.Player;
import chess.dto.MoveResultDTO;
import chess.dto.TeamDTO;
import chess.dto.TileDTO;
import chess.service.ChessService;
import spark.ModelAndView;
import spark.template.handlebars.HandlebarsTemplateEngine;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static spark.Spark.get;
import static spark.Spark.post;

public class WebChessController {
private ChessService chessService;

public void playChess() {
this.chessService = new ChessService();

get("/", (req, res) -> {
Map<String, Object> model = new HashMap<>();

return render(model, "index.html");
});

post("/name", (req, res) -> {
Map<String, Object> model = new HashMap<>();

return render(model, "name.html");
});

post("/load", (req, res) -> {
Map<String, Object> model = new HashMap<>();

try {
List<Player> players = this.chessService.players();

model.put("gameData", players);

return render(model, "table.html");
} catch (CustomSQLException e) {
model.put("errMessage", e.getMessage());
return render(model, "error.html");
}
});

post("/newGame", (req, res) -> {
Map<String, Object> model = new HashMap<>();

String whitePlayer = req.queryParams("white-player");
String blackPlayer = req.queryParams("black-player");

try {
Player player = new Player(whitePlayer, blackPlayer);
this.chessService.newGame(player);
List<TileDTO> tileDtos = this.chessService.getTiles();
TeamDTO teamDto = this.chessService.getCurrentTeam();
ChessBoard chessBoard = this.chessService.getRecentChessBoard();

model.put("tiles", tileDtos);
model.put("currentTeam", teamDto);
model.put("player", player);
model.put("chessBoard", chessBoard);

return render(model, "game.html");
} catch (CustomSQLException e) {
model.put("errMessage", e.getMessage());
return render(model, "error.html");
}
});

post("/continueGame", (req, res) -> {
Map<String, Object> model = new HashMap<>();

int chessBoardId = Integer.parseInt(req.queryParams("chess-board-id"));

try {
this.chessService.continueGame(chessBoardId);
List<TileDTO> tileDtos = this.chessService.getTiles();
TeamDTO teamDto = this.chessService.getCurrentTeam();
Player player = this.chessService.getPlayer(chessBoardId);
ChessBoard chessBoard = new ChessBoard(chessBoardId);

model.put("tiles", tileDtos);
model.put("currentTeam", teamDto);
model.put("player", player);
model.put("chessBoard", chessBoard);

return render(model, "game.html");
} catch (CustomSQLException e) {
model.put("errMessage", e.getMessage());
return render(model, "error.html");
}
});

post("/move", (req, res) -> {
Map<String, Object> model = new HashMap<>();

int chessBoardId = Integer.parseInt(req.queryParams("chess-board-id"));
String source = req.queryParams("source");
String target = req.queryParams("target");

try {
MoveResultDTO moveResultDto = this.chessService.move(chessBoardId, source, target);
List<TileDTO> tileDtos = this.chessService.getTiles();
TeamDTO teamDto = this.chessService.getCurrentTeam();
Player player = this.chessService.getPlayer(chessBoardId);
ChessBoard chessBoard = new ChessBoard(chessBoardId);

model.put("tiles", tileDtos);
model.put("currentTeam", teamDto);
model.put("message", moveResultDto.getMessage());
model.put("style", moveResultDto.getStyle());
model.put("player", player);
model.put("chessBoard", chessBoard);

if (this.chessService.isEndGame()) {
this.chessService.deleteChessGame(chessBoardId);
return render(model, "end.html");
}
return render(model, "game.html");
} catch (CustomSQLException e) {
model.put("errorMessage", e.getMessage());
return render(model, "error.html");
}
});

post("/status", (req, res) -> {
Map<String, Object> model = new HashMap<>();

int chessBoardId = Integer.parseInt(req.queryParams("chess-board-id-status"));

try {
List<TileDTO> tileDtos = this.chessService.getTiles();
TeamDTO teamDto = this.chessService.getCurrentTeam();
String message = this.chessService.getScores();
Player player = this.chessService.getPlayer(chessBoardId);
ChessBoard chessBoard = new ChessBoard(chessBoardId);

model.put("tiles", tileDtos);
model.put("currentTeam", teamDto);
model.put("message", message);
model.put("player", player);
model.put("chessBoard", chessBoard);

return render(model, "game.html");
} catch (CustomSQLException e) {
model.put("errorMessage", e.getMessage());
return render(model, "error.html");
}
});

post("/end", (req, res) -> {
Map<String, Object> model = new HashMap<>();

int chessBoardId = Integer.parseInt(req.queryParams("chess-board-id-end"));

try {
this.chessService.deleteChessGame(chessBoardId);
String message = this.chessService.getScores();

model.put("message", message);

return render(model, "end.html");
} catch (CustomSQLException e) {
model.put("errorMessage", e.getMessage());
return render(model, "error.html");
}
});
}

private static String render(Map<String, Object> model, String templatePath) {
return new HandlebarsTemplateEngine().render(new ModelAndView(model, templatePath));
}
}
Loading

0 comments on commit 86c76d6

Please sign in to comment.