diff --git a/README.md b/README.md index 0aa07befc8..73f9d62b32 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,34 @@ # 체스 3단계 - Spring Data JDBC 적용하기 ## **프로그래밍 요구사항** -- Spring Data JDBC를 활용하여 기존에 사용하던 DB에 접근하기 +- Spring Data JDBC를 활용하여 기존에 사용하던 DB에 접근하기. - 엔티티 클래스를 만들어 DB 테이블과 맵핑한다. -- Spring Data JDBC에서 제공하는 Repository를 활용하여 DB에 접근한다. \ No newline at end of file +- Spring Data JDBC에서 제공하는 Repository를 활용하여 DB에 접근한다. + +# 체스 4단계 - 동시에 여러 게임 하기 + +## **프로그래밍 요구사항** +- 체스 게임을 진행할 수 있는 방을 만들어서 동시에 여러 게임이 가능하도록 하기. + +### 체스방 만들기 + +- localhost:8080 요청 시 노출되는 페이지에 체스방을 만들 수 있는 버튼이 있다. +- 체스방 이름 입력하기 input을 추가한다. +- 체스방 만들기 버튼을 누르면 새로운 체스판이 초기화 된다. +- 체스방에는 고유식별값이 랜덤으로 부여된다. + +### 체스방 목록 조회하기 + +- localhost:8080 요청 시 체스방 목록을 조회할 수 있다 +- 체스방 목록에는 체스방 제목이 표시된다. +- 방법은 '/'로 GET 요청을 보내면 체스방에 대한 JSON이 반환된다. +- 그리고 해당 JSON을 index.js에서 처리하여 보여준다. + +### 체스방 참여하기 + +- localhost:8080 요청 시 체스방 목록에서 체스방을 클릭하면 체스 게임을 이어서 진행할 수 있다. + +### 엔티티 + +- Game : id(auto increment), UUID, name, canContinue +- History : id, start, end, gameId \ No newline at end of file diff --git a/build.gradle b/build.gradle index a234ac906d..9c9b7bbd27 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,6 @@ dependencies { implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.1' implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.google.code.gson:gson:2.8.6' compile('com.sparkjava:spark-core:2.9.0') compile('com.sparkjava:spark-template-handlebars:2.7.1') compile('ch.qos.logback:logback-classic:1.2.3') diff --git a/src/main/java/wooteco/chess/controller/SparkChessController.java b/src/main/java/wooteco/chess/controller/SparkChessController.java index 67b06f15ef..fc9e0d2bf3 100644 --- a/src/main/java/wooteco/chess/controller/SparkChessController.java +++ b/src/main/java/wooteco/chess/controller/SparkChessController.java @@ -70,7 +70,8 @@ private String postBoard(Request req, Response res) { Map model = new HashMap<>(); try { - MoveStatusDto moveStatusDto = sparkChessService.move(new MovingPosition(req.queryParams("source"), req.queryParams("destination"))); + MoveStatusDto moveStatusDto = sparkChessService.move(new MovingPosition(req.queryParams("source"), + req.queryParams("destination"))); model.put("normalStatus", moveStatusDto.getNormalStatus()); model.put("winner", moveStatusDto.getWinner()); @@ -108,7 +109,8 @@ private Map getMovablePositions(Request req, Response res) throw private Map move(Request req, Response res) { Map model = new HashMap<>(); - DestinationPositionDto destinationPositionDto = sparkChessService.chooseDestinationPosition(req.queryParams("destination")); + DestinationPositionDto destinationPositionDto = sparkChessService.chooseDestinationPosition( + req.queryParams("destination")); model.put("normalStatus", destinationPositionDto.getNormalStatus().isNormalStatus()); model.put("position", destinationPositionDto.getPosition()); diff --git a/src/main/java/wooteco/chess/controller/SpringChessController.java b/src/main/java/wooteco/chess/controller/SpringChessController.java index 6f96a4716f..3b7d4593cf 100644 --- a/src/main/java/wooteco/chess/controller/SpringChessController.java +++ b/src/main/java/wooteco/chess/controller/SpringChessController.java @@ -7,94 +7,115 @@ import wooteco.chess.domain.game.NormalStatus; import wooteco.chess.domain.position.MovingPosition; import wooteco.chess.dto.ChessGameDto; +import wooteco.chess.dto.GamesDto; import wooteco.chess.dto.MovablePositionsDto; import wooteco.chess.dto.MoveStatusDto; import wooteco.chess.service.SpringDataJDBCChessService; import wooteco.chess.web.JsonTransformer; -import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @Controller public class SpringChessController { - @Autowired - private SpringDataJDBCChessService springChessService; + @Autowired + private SpringDataJDBCChessService springDataJDBCChessService; - @GetMapping("/") - public ModelAndView routeMainPage() { - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName("index"); - modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus()); - return modelAndView; - } + @GetMapping("/") + public ModelAndView routeMainPage() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("index"); + modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus()); + return modelAndView; + } - @GetMapping("/new") - public ModelAndView startNewGame() throws SQLException { - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName("chess"); - modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus()); - springChessService.clearHistory(); - return modelAndView; - } + @GetMapping("/games") + @ResponseBody + public String showGames() { + GamesDto games = springDataJDBCChessService.selectAvailableGames(); + return JsonTransformer.toJson(games); + } - @GetMapping("/board") - @ResponseBody - public String setBoard() throws SQLException { - ChessGameDto chessGameDto = springChessService.setBoard(); - return JsonTransformer.toJson(chessGameDto); - } + @PostMapping("/new") + @ResponseBody + public String saveNewGame(@RequestBody Map param) { + System.out.println(param.get("gameName")); + ChessGameDto chessGameDto = springDataJDBCChessService.createGameBy((String) param.get("gameName")); - @GetMapping("/source") - @ResponseBody - public String getMovablePositions(@RequestParam String source) throws SQLException { - Map model = new HashMap<>(); - try { - MovablePositionsDto movablePositionsDto = springChessService.findMovablePositions(source); - model.put("movable", movablePositionsDto.getMovablePositionNames()); - model.put("position", movablePositionsDto.getPosition()); - model.put("normalStatus", NormalStatus.YES.isNormalStatus()); - return JsonTransformer.toJson(model); - } catch (IllegalArgumentException | UnsupportedOperationException | NullPointerException e) { - model.put("normalStatus", NormalStatus.NO.isNormalStatus()); - model.put("exception", e.getMessage()); - return JsonTransformer.toJson(model); - } - } + return JsonTransformer.toJson(chessGameDto); + } - @GetMapping("/destination") - @ResponseBody - public String checkMovable(@RequestParam String startPosition, @RequestParam String destination) { - Map model = new HashMap<>(); - MoveStatusDto moveStatusDto = springChessService.checkMovable( - new MovingPosition(startPosition, destination)); + @GetMapping("/game/{id}") + @ResponseBody + public ModelAndView startGame() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("chess"); + modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus()); + return modelAndView; + } - model.put("normalStatus", moveStatusDto.getNormalStatus()); - model.put("exception", moveStatusDto.getException()); - return JsonTransformer.toJson(model); - } + @GetMapping("/board/{id}") + @ResponseBody + public String setBoard(@PathVariable Long id) { + ChessGameDto chessGameDto = springDataJDBCChessService.setBoardBy(id); + return JsonTransformer.toJson(chessGameDto); + } - @PostMapping("/board") - public ModelAndView saveHistory(@RequestBody MovingPosition movingPosition) throws SQLException { - ModelAndView modelAndView = new ModelAndView(); + @GetMapping("/board/{id}/source") + @ResponseBody + public String getMovablePositions(@PathVariable Long id, @RequestParam String source) { + Map model = new HashMap<>(); + try { + MovablePositionsDto movablePositionsDto = springDataJDBCChessService.findMovablePositions(id, source); + model.put("movable", movablePositionsDto.getMovablePositionNames()); + model.put("position", movablePositionsDto.getPosition()); + model.put("normalStatus", NormalStatus.YES.isNormalStatus()); + return JsonTransformer.toJson(model); + } catch (IllegalArgumentException | UnsupportedOperationException | NullPointerException e) { + model.put("normalStatus", NormalStatus.NO.isNormalStatus()); + model.put("exception", e.getMessage()); + return JsonTransformer.toJson(model); + } + } - MoveStatusDto moveStatusDto = springChessService.move(movingPosition); - if (moveStatusDto.getWinner().isNone()) { - modelAndView.setViewName("chess"); - return modelAndView; - } - modelAndView.setViewName("result"); - modelAndView.addObject("winner", moveStatusDto.getWinner()); - springChessService.clearHistory(); - return modelAndView; - } + @GetMapping("/board/{id}/destination") + @ResponseBody + public String checkMovable(@PathVariable Long id, @RequestParam String startPosition, + @RequestParam String destination) { + Map model = new HashMap<>(); + MoveStatusDto moveStatusDto = springDataJDBCChessService.checkMovable(id, + new MovingPosition(startPosition, destination)); - @GetMapping("/loading") - public ModelAndView loadGame() { - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName("chess"); - modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus()); + model.put("normalStatus", moveStatusDto.getNormalStatus()); + model.put("exception", moveStatusDto.getException()); + return JsonTransformer.toJson(model); + } - return modelAndView; - } + @PostMapping("/board/{id}") + @ResponseBody + public String saveHistory(@PathVariable Long id, @RequestBody MovingPosition movingPosition) { + try { + MoveStatusDto moveStatusDto = springDataJDBCChessService.move(id, movingPosition); + return JsonTransformer.toJson(moveStatusDto); + } catch (IllegalArgumentException e) { + MoveStatusDto moveStatusDto = new MoveStatusDto(false, e.getMessage()); + return JsonTransformer.toJson(moveStatusDto); + } + } + + @GetMapping("/loading/{id}") + public ModelAndView loadGame() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("chess"); + modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus()); + return modelAndView; + } + + @GetMapping("/result/{winner}") + public ModelAndView showResult(@PathVariable String winner) { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("result"); + modelAndView.addObject("winner", winner); + return modelAndView; + } } \ No newline at end of file diff --git a/src/main/java/wooteco/chess/dto/BoardDto.java b/src/main/java/wooteco/chess/dto/BoardDto.java index 6fa8de5de8..e0acf4c791 100644 --- a/src/main/java/wooteco/chess/dto/BoardDto.java +++ b/src/main/java/wooteco/chess/dto/BoardDto.java @@ -4,6 +4,7 @@ import wooteco.chess.domain.piece.pieces.Pieces; import wooteco.chess.domain.position.Position; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -17,6 +18,6 @@ public BoardDto(Pieces pieces) { } public Map getBoard() { - return board; + return Collections.unmodifiableMap(board); } } \ No newline at end of file diff --git a/src/main/java/wooteco/chess/dto/ChessGameDto.java b/src/main/java/wooteco/chess/dto/ChessGameDto.java index 9fb3f033ae..752f7e79d5 100644 --- a/src/main/java/wooteco/chess/dto/ChessGameDto.java +++ b/src/main/java/wooteco/chess/dto/ChessGameDto.java @@ -4,10 +4,11 @@ import wooteco.chess.domain.game.Turn; public class ChessGameDto { - private BoardDto boardDto; - private Turn turn; - private ScoreResult score; - private boolean normalStatus; + private Long gameId; + private final BoardDto boardDto; + private final Turn turn; + private final ScoreResult score; + private final boolean normalStatus; public ChessGameDto(BoardDto boardDto, Turn turn, ScoreResult score, boolean normalStatus) { this.boardDto = boardDto; @@ -16,6 +17,18 @@ public ChessGameDto(BoardDto boardDto, Turn turn, ScoreResult score, boolean nor this.normalStatus = normalStatus; } + public ChessGameDto(Long gameId, BoardDto boardDto, Turn turn, ScoreResult score, boolean normalStatus) { + this.gameId = gameId; + this.boardDto = boardDto; + this.turn = turn; + this.score = score; + this.normalStatus = normalStatus; + } + + public Long getGameId() { + return gameId; + } + public BoardDto getBoardDto() { return boardDto; } diff --git a/src/main/java/wooteco/chess/dto/DestinationPositionDto.java b/src/main/java/wooteco/chess/dto/DestinationPositionDto.java index c11a65099f..e6e186d038 100644 --- a/src/main/java/wooteco/chess/dto/DestinationPositionDto.java +++ b/src/main/java/wooteco/chess/dto/DestinationPositionDto.java @@ -3,8 +3,8 @@ import wooteco.chess.domain.game.NormalStatus; public class DestinationPositionDto { - private String position; - private NormalStatus normalStatus; + private final String position; + private final NormalStatus normalStatus; public DestinationPositionDto(String position, NormalStatus normalStatus) { this.position = position; diff --git a/src/main/java/wooteco/chess/dto/GamesDto.java b/src/main/java/wooteco/chess/dto/GamesDto.java new file mode 100644 index 0000000000..ac7e64e8b3 --- /dev/null +++ b/src/main/java/wooteco/chess/dto/GamesDto.java @@ -0,0 +1,16 @@ +package wooteco.chess.dto; + +import java.util.Collections; +import java.util.Map; + +public class GamesDto { + private final Map games; + + public GamesDto(Map games) { + this.games = games; + } + + public Map getGames() { + return Collections.unmodifiableMap(games); + } +} diff --git a/src/main/java/wooteco/chess/dto/MovablePositionsDto.java b/src/main/java/wooteco/chess/dto/MovablePositionsDto.java index 81af3719ee..6fdd7b38a7 100644 --- a/src/main/java/wooteco/chess/dto/MovablePositionsDto.java +++ b/src/main/java/wooteco/chess/dto/MovablePositionsDto.java @@ -1,10 +1,11 @@ package wooteco.chess.dto; +import java.util.Collections; import java.util.List; public class MovablePositionsDto { - private List movablePositionNames; - private String position; + private final List movablePositionNames; + private final String position; public MovablePositionsDto(List movablePositionNames, String position) { this.movablePositionNames = movablePositionNames; @@ -12,7 +13,7 @@ public MovablePositionsDto(List movablePositionNames, String position) { } public List getMovablePositionNames() { - return movablePositionNames; + return Collections.unmodifiableList(movablePositionNames); } public String getPosition() { diff --git a/src/main/java/wooteco/chess/dto/MoveStatusDto.java b/src/main/java/wooteco/chess/dto/MoveStatusDto.java index dd75f33145..21b50a26a6 100644 --- a/src/main/java/wooteco/chess/dto/MoveStatusDto.java +++ b/src/main/java/wooteco/chess/dto/MoveStatusDto.java @@ -5,9 +5,9 @@ public class MoveStatusDto { private static final String EMPTY_STRING = ""; - private boolean normalStatus; - private Color winner; - private String exception; + private final boolean normalStatus; + private final Color winner; + private final String exception; public MoveStatusDto(boolean normalStatus, String exception) { this.normalStatus = normalStatus; diff --git a/src/main/java/wooteco/chess/entity/Game.java b/src/main/java/wooteco/chess/entity/Game.java new file mode 100644 index 0000000000..6de7a89a4a --- /dev/null +++ b/src/main/java/wooteco/chess/entity/Game.java @@ -0,0 +1,69 @@ +package wooteco.chess.entity; + +import org.springframework.data.annotation.Id; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public class Game { + @Id + private Long id; + private String name; + private Boolean canContinue; + private Set histories = new HashSet<>(); + + public Game() { + } + + public Game(Long id, String name, Boolean canContinue) { + this.id = id; + this.name = name; + this.canContinue = canContinue; + } + + public Game(String gameName, Boolean canContinue) { + this.name = gameName; + this.canContinue = canContinue; + } + + public void addHistory(History history) { + histories.add(history); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Boolean getCanContinue() { + return canContinue; + } + + public Set getHistories() { + return Collections.unmodifiableSet(histories); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Game game = (Game) o; + return Objects.equals(id, game.id) && + Objects.equals(name, game.name) && + Objects.equals(canContinue, game.canContinue); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, canContinue); + } +} diff --git a/src/main/java/wooteco/chess/entity/GameRepository.java b/src/main/java/wooteco/chess/entity/GameRepository.java new file mode 100644 index 0000000000..889f9ea0f4 --- /dev/null +++ b/src/main/java/wooteco/chess/entity/GameRepository.java @@ -0,0 +1,13 @@ +package wooteco.chess.entity; + +import org.springframework.data.jdbc.repository.query.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface GameRepository extends CrudRepository { + @Query("SELECT * FROM game WHERE can_continue = true") + List findAvailableGames(); +} diff --git a/src/main/java/wooteco/chess/entity/History.java b/src/main/java/wooteco/chess/entity/History.java index fc56fa85be..f73ae24766 100644 --- a/src/main/java/wooteco/chess/entity/History.java +++ b/src/main/java/wooteco/chess/entity/History.java @@ -1,14 +1,12 @@ package wooteco.chess.entity; import org.springframework.data.annotation.Id; -import org.springframework.data.relational.core.mapping.Column; -import org.springframework.data.relational.core.mapping.Table; -@Table("history") public class History { - private @Id Long id; - private @Column("start") String start; - private @Column("end") String end; + @Id + private Long id; + private String start; + private String end; public History() { } diff --git a/src/main/java/wooteco/chess/entity/HistoryRepository.java b/src/main/java/wooteco/chess/entity/HistoryRepository.java deleted file mode 100644 index 7ba2f22cbc..0000000000 --- a/src/main/java/wooteco/chess/entity/HistoryRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package wooteco.chess.entity; - -import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface HistoryRepository extends CrudRepository { - @Override - List findAll(); -} diff --git a/src/main/java/wooteco/chess/service/SparkChessService.java b/src/main/java/wooteco/chess/service/SparkChessService.java index 90db39e6a8..19e73372e9 100644 --- a/src/main/java/wooteco/chess/service/SparkChessService.java +++ b/src/main/java/wooteco/chess/service/SparkChessService.java @@ -22,7 +22,8 @@ public ChessGameDto setBoard() throws SQLException { load(chessGame); - return new ChessGameDto(new BoardDto(chessGame.getPieces()), chessGame.getTurn(), chessGame.calculateScore(), NormalStatus.YES.isNormalStatus()); + return new ChessGameDto(new BoardDto(chessGame.getPieces()), chessGame.getTurn(), chessGame.calculateScore(), + NormalStatus.YES.isNormalStatus()); } private void load(ChessGame chessGame) throws SQLException { @@ -49,7 +50,8 @@ public MoveStatusDto move(MovingPosition movingPosition) throws SQLException { chessGame.move(movingPosition); if (chessGame.isKingDead()) { - MoveStatusDto moveStatusDto = new MoveStatusDto(NormalStatus.YES.isNormalStatus(), chessGame.getAliveKingColor()); + MoveStatusDto moveStatusDto = new MoveStatusDto(NormalStatus.YES.isNormalStatus(), + chessGame.getAliveKingColor()); clearHistory(); return moveStatusDto; } diff --git a/src/main/java/wooteco/chess/service/SpringChessService.java b/src/main/java/wooteco/chess/service/SpringChessService.java deleted file mode 100644 index 9601f18984..0000000000 --- a/src/main/java/wooteco/chess/service/SpringChessService.java +++ /dev/null @@ -1,86 +0,0 @@ -package wooteco.chess.service; - -import org.springframework.stereotype.Service; -import wooteco.chess.dao.FakeHistoryDao; -import wooteco.chess.dao.HistoryDao; -import wooteco.chess.domain.game.ChessGame; -import wooteco.chess.domain.game.NormalStatus; -import wooteco.chess.domain.position.MovingPosition; -import wooteco.chess.dto.BoardDto; -import wooteco.chess.dto.ChessGameDto; -import wooteco.chess.dto.MovablePositionsDto; -import wooteco.chess.dto.MoveStatusDto; - -import java.sql.SQLException; -import java.util.List; - -@Service -public class SpringChessService { - HistoryDao historyDao = new FakeHistoryDao(); - - public void clearHistory() throws SQLException { - historyDao.clear(); - } - - public ChessGameDto setBoard() throws SQLException { - ChessGame chessGame = new ChessGame(); - - load(chessGame); - - return new ChessGameDto(new BoardDto(chessGame.getPieces()), chessGame.getTurn(), chessGame.calculateScore(), NormalStatus.YES.isNormalStatus()); - } - - private void load(ChessGame chessGame) throws SQLException { - List histories = selectAllHistory(); - - for (MovingPosition movingPosition : histories) { - chessGame.move(movingPosition); - } - } - - private List selectAllHistory() throws SQLException { - return historyDao.selectAll(); - } - - public MovablePositionsDto findMovablePositions(String source) throws SQLException { - ChessGame chessGame = new ChessGame(); - load(chessGame); - - List movablePositionNames = chessGame.findMovablePositionNames(source); - - return new MovablePositionsDto(movablePositionNames, source); - - } - - public MoveStatusDto checkMovable(MovingPosition movingPosition) { - try { - ChessGame chessGame = new ChessGame(); - - load(chessGame); - chessGame.move(movingPosition); - return new MoveStatusDto(NormalStatus.YES.isNormalStatus()); - } catch (IllegalArgumentException | UnsupportedOperationException | NullPointerException | SQLException e) { - return new MoveStatusDto(NormalStatus.NO.isNormalStatus(), e.getMessage()); - } - } - - public MoveStatusDto move(MovingPosition movingPosition) throws SQLException { - ChessGame chessGame = new ChessGame(); - load(chessGame); - chessGame.move(movingPosition); - - MoveStatusDto moveStatusDto = new MoveStatusDto(NormalStatus.YES.isNormalStatus()); - - if (chessGame.isKingDead()) { - moveStatusDto = new MoveStatusDto(NormalStatus.YES.isNormalStatus(), chessGame.getAliveKingColor()); - } - - insertHistory(movingPosition); - - return moveStatusDto; - } - - private void insertHistory(MovingPosition movingPosition) throws SQLException { - historyDao.insert(movingPosition); - } -} diff --git a/src/main/java/wooteco/chess/service/SpringDataJDBCChessService.java b/src/main/java/wooteco/chess/service/SpringDataJDBCChessService.java index acc201e345..14fb3fa6ea 100644 --- a/src/main/java/wooteco/chess/service/SpringDataJDBCChessService.java +++ b/src/main/java/wooteco/chess/service/SpringDataJDBCChessService.java @@ -5,63 +5,69 @@ import wooteco.chess.domain.game.ChessGame; import wooteco.chess.domain.game.NormalStatus; import wooteco.chess.domain.position.MovingPosition; -import wooteco.chess.dto.BoardDto; -import wooteco.chess.dto.ChessGameDto; -import wooteco.chess.dto.MovablePositionsDto; -import wooteco.chess.dto.MoveStatusDto; +import wooteco.chess.dto.*; +import wooteco.chess.entity.Game; +import wooteco.chess.entity.GameRepository; import wooteco.chess.entity.History; -import wooteco.chess.entity.HistoryRepository; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Service public class SpringDataJDBCChessService { @Autowired - private HistoryRepository historyRepository; + private GameRepository gameRepository; - public void clearHistory() { - historyRepository.deleteAll(); - } - - public ChessGameDto setBoard() { + public ChessGameDto createGameBy(String gameName) { ChessGame chessGame = new ChessGame(); + Long gameId = save(gameName); + return new ChessGameDto(gameId, new BoardDto(chessGame.getPieces()), chessGame.getTurn(), + chessGame.calculateScore(), NormalStatus.YES.isNormalStatus()); + } - load(chessGame); - - return new ChessGameDto(new BoardDto(chessGame.getPieces()), chessGame.getTurn(), chessGame.calculateScore(), NormalStatus.YES.isNormalStatus()); + private Long save(String gameName) { + Game game = gameRepository.save(new Game(gameName, true)); + return game.getId(); } - private void load(ChessGame chessGame) { - List histories = selectAllHistory(); + public ChessGameDto setBoardBy(Long id) { + ChessGame chessGame = new ChessGame(); + load(chessGame, id); + return new ChessGameDto(id, new BoardDto(chessGame.getPieces()), chessGame.getTurn(), + chessGame.calculateScore(), NormalStatus.YES.isNormalStatus()); + } + private void load(ChessGame chessGame, Long id) { + List histories = selectAllHistoryBy(id); for (MovingPosition movingPosition : histories) { chessGame.move(movingPosition); } } - private List selectAllHistory() { - return Collections.unmodifiableList(historyRepository.findAll().stream() - .map(history -> new MovingPosition(history.getStart(), history.getEnd())) + private List selectAllHistoryBy(Long id) { + Game game = gameRepository.findById(id).orElseThrow(() -> + new IllegalArgumentException("없는 게임 id 입니다.")); + Set histories = game.getHistories(); + + return Collections.unmodifiableList(histories.stream() + .map(h -> new MovingPosition(h.getStart(), h.getEnd())) .collect(Collectors.toList())); } - public MovablePositionsDto findMovablePositions(String source) { + public MovablePositionsDto findMovablePositions(Long id, String source) { ChessGame chessGame = new ChessGame(); - load(chessGame); + load(chessGame, id); List movablePositionNames = chessGame.findMovablePositionNames(source); return new MovablePositionsDto(movablePositionNames, source); - } - public MoveStatusDto checkMovable(MovingPosition movingPosition) { + public MoveStatusDto checkMovable(Long id, MovingPosition movingPosition) { try { ChessGame chessGame = new ChessGame(); - load(chessGame); + load(chessGame, id); chessGame.move(movingPosition); return new MoveStatusDto(NormalStatus.YES.isNormalStatus()); } catch (IllegalArgumentException | UnsupportedOperationException | NullPointerException e) { @@ -69,24 +75,43 @@ public MoveStatusDto checkMovable(MovingPosition movingPosition) { } } - public MoveStatusDto move(MovingPosition movingPosition) { + public MoveStatusDto move(Long id, MovingPosition movingPosition) throws IllegalArgumentException { ChessGame chessGame = new ChessGame(); - load(chessGame); + load(chessGame, id); chessGame.move(movingPosition); MoveStatusDto moveStatusDto = new MoveStatusDto(NormalStatus.YES.isNormalStatus()); if (chessGame.isKingDead()) { + updateCanContinueToFalse(id); moveStatusDto = new MoveStatusDto(NormalStatus.YES.isNormalStatus(), chessGame.getAliveKingColor()); } - insertHistory(movingPosition); + insertHistory(id, movingPosition); return moveStatusDto; } - private void insertHistory(MovingPosition movingPosition) { + private void updateCanContinueToFalse(Long id) { + Game game = gameRepository.findById(id) + .orElseThrow(() -> + new IllegalArgumentException("해당 id의 방이 없습니다.")); + gameRepository.save(new Game(game.getId(), game.getName(), false)); + } + + private void insertHistory(Long id, MovingPosition movingPosition) { + Game game = gameRepository.findById(id) + .orElseThrow(() -> + new IllegalArgumentException("해당 id의 방이 없습니다.")); History history = new History(movingPosition.getStart(), movingPosition.getEnd()); - historyRepository.save(history); + game.addHistory(history); + gameRepository.save(game); + } + + public GamesDto selectAvailableGames() { + Map games = gameRepository.findAvailableGames().stream() + .collect(Collectors.toMap(game -> game.getId(), game -> game.getName(), + (e1, e2) -> e1, LinkedHashMap::new)); + return new GamesDto(games); } } diff --git a/src/main/java/wooteco/chess/web/ConnectionManager.java b/src/main/java/wooteco/chess/web/ConnectionManager.java index 4450ac87ba..d028c4471d 100644 --- a/src/main/java/wooteco/chess/web/ConnectionManager.java +++ b/src/main/java/wooteco/chess/web/ConnectionManager.java @@ -5,31 +5,32 @@ import java.sql.SQLException; public class ConnectionManager { - public Connection getConnection() { - Connection con = null; - String server = "localhost:13306"; // MySQL 서버 주소 - String database = "chess"; // MySQL DATABASE 이름 - String option = "?useSSL=false&serverTimezone=UTC"; - String userName = "root"; // MySQL 서버 아이디 - String password = "root"; // MySQL 서버 비밀번호 + public Connection getConnection() { + Connection con = null; + String server = "localhost:13306"; // MySQL 서버 주소 + String database = "chess"; // MySQL DATABASE 이름 + String option = "?useSSL=false&serverTimezone=UTC"; + String userName = "root"; // MySQL 서버 아이디 + String password = "root"; // MySQL 서버 비밀번호 - // 드라이버 로딩 - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - System.err.println(" !! JDBC Driver load 오류: " + e.getMessage()); - e.printStackTrace(); - } + // 드라이버 로딩 + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + System.err.println(" !! JDBC Driver load 오류: " + e.getMessage()); + e.printStackTrace(); + } - // 드라이버 연결 - try { - con = DriverManager.getConnection("jdbc:mysql://" + server + "/" + database + option, userName, password); - System.out.println("정상적으로 연결되었습니다."); - } catch (SQLException e) { - System.err.println("연결 오류:" + e.getMessage()); - e.printStackTrace(); - } + // 드라이버 연결 + try { + con = DriverManager.getConnection("jdbc:mysql://" + server + "/" + database + option, userName, + password); + System.out.println("정상적으로 연결되었습니다."); + } catch (SQLException e) { + System.err.println("연결 오류:" + e.getMessage()); + e.printStackTrace(); + } - return con; - } + return con; + } } diff --git a/src/main/java/wooteco/chess/web/JsonTransformer.java b/src/main/java/wooteco/chess/web/JsonTransformer.java index 3fd1eede18..de6ea09517 100644 --- a/src/main/java/wooteco/chess/web/JsonTransformer.java +++ b/src/main/java/wooteco/chess/web/JsonTransformer.java @@ -5,11 +5,11 @@ public class JsonTransformer { - public static String toJson(Object object) { - return new Gson().toJson(object); - } + public static String toJson(Object object) { + return new Gson().toJson(object); + } - public static ResponseTransformer json() { - return JsonTransformer::toJson; - } + public static ResponseTransformer json() { + return JsonTransformer::toJson; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a21076509d..2ed3c334a4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -4,5 +4,4 @@ spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:13306/chess?useSSL=fa spring.datasource.username=root spring.datasource.password=root logging.level.org.springframework.jdbc=TRACE -# 제이슨의 도움으로 해결 spring.datasource.initialization-mode=ALWAYS diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 5de8649aba..54ab188ce3 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,6 +1,15 @@ -create table history ( - id bigint not null auto_increment, - start varchar(2) not null, - end varchar(2) not null, - primary key(id) +CREATE TABLE IF NOT EXISTS game ( + id BIGINT NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + can_continue BOOL NOT NULL, + PRIMARY KEY(id) +); + +CREATE TABLE IF NOT EXISTS history ( + id BIGINT NOT NULL AUTO_INCREMENT, + start VARCHAR(2) NOT NULL, + end VARCHAR(2) NOT NULL, + game BIGINT NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(game) REFERENCES game(id) ); \ No newline at end of file diff --git a/src/main/resources/static/public/css/chess.css b/src/main/resources/static/public/css/chess.css index 28f35f6d4a..90f66f9f59 100644 --- a/src/main/resources/static/public/css/chess.css +++ b/src/main/resources/static/public/css/chess.css @@ -1,3 +1,20 @@ +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz); +@import url(//fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); +@import url(//fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic); +@import url(//fonts.googleapis.com/earlyaccess/hanna.css); + +@font-face { + font-family: "BMHANNAAir"; + src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_four@1.0/BMHANNAAir.woff") format("woff"); + font-weight: bold; + font-style: normal; +} + +* { + font-family: BMHANNAAir; + font-size: 30px; +} + .title { justify-content: center; background-color: gray; @@ -56,3 +73,8 @@ height: 20px; padding: 0; } + +.exit { + margin: 8px auto auto; + text-align: center; +} diff --git a/src/main/resources/static/public/css/index.css b/src/main/resources/static/public/css/index.css index 76f77421f2..72328f4380 100644 --- a/src/main/resources/static/public/css/index.css +++ b/src/main/resources/static/public/css/index.css @@ -1,3 +1,20 @@ +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz); +@import url(//fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); +@import url(//fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic); +@import url(//fonts.googleapis.com/earlyaccess/hanna.css); + +@font-face { + font-family: "BMHANNAAir"; + src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_four@1.0/BMHANNAAir.woff") format("woff"); + font-weight: bold; + font-style: normal; +} + +* { + font-family: BMHANNAAir; + font-size: 30px; +} + h1 { color: blue; font-size: 48px; @@ -8,8 +25,12 @@ h1 { text-align: center; } -#new a { - font-size: 32px; +#start-btn { + width: 200px; + height: 100px; + border-radius: 5px; + border: solid 1px; + font-size: 20px; } #loading { @@ -18,4 +39,18 @@ h1 { #loading a { font-size: 32px; +} + +#loading-table { + border: 1px solid black; + text-align: center; + margin: 2em auto auto; +} + +#loading-table th, +#loading-table td { + border: 1px solid black; + height: 50px; + width: 50px; + text-align: center; } \ No newline at end of file diff --git a/src/main/resources/static/public/css/result.css b/src/main/resources/static/public/css/result.css index c69384af46..7fa9d95242 100644 --- a/src/main/resources/static/public/css/result.css +++ b/src/main/resources/static/public/css/result.css @@ -1,10 +1,34 @@ +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz); +@import url(//fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); +@import url(//fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic); +@import url(//fonts.googleapis.com/earlyaccess/hanna.css); + +@font-face { + font-family: "BMHANNAAir"; + src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_four@1.0/BMHANNAAir.woff") format("woff"); + font-weight: bold; + font-style: normal; +} + +* { + font-family: BMHANNAAir; + font-size: 30px; +} + .result { margin: 0 auto; text-align: center; + margin-top: 2em; } .result p { font-size: 32px; + margin: 0 auto; +} + +.result button { + font-size: 32px; + margin: 0 auto; } #go-main { diff --git a/src/main/resources/static/public/js/chess.js b/src/main/resources/static/public/js/chess.js index 3c0e7cf774..c3bfe2cf72 100644 --- a/src/main/resources/static/public/js/chess.js +++ b/src/main/resources/static/public/js/chess.js @@ -1,131 +1,149 @@ window.onload = function () { - const PIECES = { - BLACK_KING: ``, - BLACK_QUEEN: ``, - BLACK_ROOK: ``, - BLACK_BISHOP: ``, - BLACK_KNIGHT: ``, - BLACK_BLACK_PAWN: ``, - WHITE_KING: ``, - WHITE_QUEEN: ``, - WHITE_ROOK: ``, - WHITE_BISHOP: ``, - WHITE_KNIGHT: ``, - WHITE_WHITE_PAWN: ``, - }; - let startPosition = null; + const PIECES = { + BLACK_KING: ``, + BLACK_QUEEN: ``, + BLACK_ROOK: ``, + BLACK_BISHOP: ``, + BLACK_KNIGHT: ``, + BLACK_BLACK_PAWN: ``, + WHITE_KING: ``, + WHITE_QUEEN: ``, + WHITE_ROOK: ``, + WHITE_BISHOP: ``, + WHITE_KNIGHT: ``, + WHITE_WHITE_PAWN: ``, + }; + let startPosition = null; + let pathName; - async function getChessGame() { - const response = await fetch("http://localhost:8080/board"); - return await response.json(); - } + async function getChessGame() { + let path = window.location.pathname; + pathName = path.substring(path.lastIndexOf("/") + 1); + const response = await fetch(`http://localhost:8080/board/${pathName}`); + return await response.json(); + } - function setBoard(board) { - document.querySelectorAll(".position").forEach(element => { - while (element.lastElementChild) { - element.removeChild(element.lastElementChild); - } - }); - Object.keys(board) - .filter(position => board[position]["pieceType"] !== "BLANK") - .forEach(position => { - const color = board[position]["color"]; - const pieceType = board[position]["pieceType"]; - document.getElementById(position) - .insertAdjacentHTML("beforeend", PIECES[`${color}_${pieceType}`]); - }); - } + function setBoard(board) { + document.querySelectorAll(".position").forEach(element => { + while (element.lastElementChild) { + element.removeChild(element.lastElementChild); + } + }); + Object.keys(board) + .filter(position => board[position]["pieceType"] !== "BLANK") + .forEach(position => { + const color = board[position]["color"]; + const pieceType = board[position]["pieceType"]; + document.getElementById(position) + .insertAdjacentHTML("beforeend", PIECES[`${color}_${pieceType}`]); + }); + } - function setTurn(turn) { - document.getElementById("turn_box") - .innerHTML = '

' + turn["color"] + "의 턴입니다." + '

'; - } + function setTurn(turn) { + document.getElementById("turn_box") + .innerHTML = '

' + turn["color"] + "의 턴입니다." + '

'; + } - function setScore(score) { - document.getElementById("score") - .innerHTML = '

' + - "WHITE 팀의 점수는 " + score["WHITE"] + "점 입니다.\n" + - "BLACK 팀의 점수는 " + score["BLACK"] + "점 입니다." + - '

'; - } + function setScore(score) { + document.getElementById("score") + .innerHTML = '

' + + "WHITE 팀의 점수는 " + score["WHITE"] + "점 입니다.\n" + + "BLACK 팀의 점수는 " + score["BLACK"] + "점 입니다." + + '

'; + } - (async function () { - const chessGame = await getChessGame(); - const board = chessGame["boardDto"]["board"]; - const turn = chessGame["turn"]; - const score = chessGame["score"]["scores"]; + (async function () { + const chessGame = await getChessGame(); + const board = await chessGame["boardDto"]["board"]; + const turn = chessGame["turn"]; + const score = chessGame["score"]["scores"]; - if (chessGame["normalStatus"] === false) { - alert("잘못된 명령입니다."); - return; - } - setBoard(board); - setTurn(turn); - setScore(score); - })(); + if (chessGame["normalStatus"] === false) { + alert("잘못된 명령입니다."); + return; + } + setBoard(board); + setTurn(turn); + setScore(score); + })(); - function chooseFirstPosition(position) { - fetch(`http://localhost:8080/source?source=${position}`, {method: "GET"}) - .then(res => res.json()) - .then(data => { - startPosition = data.position; - console.log(data.normalStatus); - if (data.normalStatus === false) { - alert(data.exception); - startPosition = null; - return; - } - const positions = data.movable; - positions.forEach(position => { - document.getElementById(position) - .style - .backgroundColor = "rgba(255, 100, 0, 0.2)"; - }); + function chooseFirstPosition(position) { + fetch(`http://localhost:8080/board/${pathName}/source?source=${position}`, + {method: "GET"}) + .then(res => res.json()) + .then(data => { + startPosition = data.position; + if (data.normalStatus === false) { + alert(data.exception); + startPosition = null; + return; + } + const positions = data.movable; + positions.forEach(position => { + document.getElementById(position) + .style + .backgroundColor = "rgba(255, 100, 0, 0.2)"; + }); - document.getElementById(position) - .style - .backgroundColor = "rgba(255, 200, 0, 0.2)"; - }); - } + document.getElementById(position) + .style + .backgroundColor = "rgba(255, 200, 0, 0.2)"; + }); + } - function chooseSecondPosition(position) { - fetch(`http://localhost:8080/destination?destination=${position}&startPosition=${startPosition}`, - {method: "GET"}) - .then(res => res.json()) - .then(async data => { - if (data.normalStatus === false) { - alert(data.exception); - startPosition = null; - window.location.href = "/loading"; - return; - } - const source = startPosition; - const destination = position; - startPosition = null; + function chooseSecondPosition(position) { + fetch(`http://localhost:8080/board/${pathName}/destination?destination=${position}&startPosition=${startPosition}`, + {method: "GET"}) + .then(function (response) { + return response.json(); + }) + .then(data => { + if (data.normalStatus === false) { + alert(data.exception); + startPosition = null; + window.location.href = `/loading/${pathName}`; + return; + } + const source = startPosition; + const destination = position; + startPosition = null; - await fetch("http://localhost:8080/board", { - method: "POST", - body: JSON.stringify({ - start: source, - end: destination - }), - headers: {"Content-Type": "application/json"} - }) - .then(window.location.href = "/loading"); - }); - } + fetch(`http://localhost:8080/board/${pathName}`, { + method: "POST", + body: JSON.stringify({ + start: source, + end: destination + }), + headers: {"Content-Type": "application/json"} + }) + .then(function (winnerResponse) { + return winnerResponse.json(); + }) + .then(winnerData => { + if (!winnerData["normalStatus"]) { + alert(winnerData["exception"]); + return location.href = "/"; + } + if (winnerData["winner"] !== "NONE") { + let winnerTeam = winnerData["winner"]; + return location.href = `/result/${winnerTeam}`; + } + location.href = `/loading/${pathName}`; + }) + }); + } - document.querySelectorAll(".position").forEach( - element => { - element.addEventListener("click", (e) => { - let position = e.currentTarget.id; - e.preventDefault(); - if (startPosition == null) { - chooseFirstPosition(position); - } else { - chooseSecondPosition(position); - } - }); + document.querySelectorAll(".position").forEach( + element => { + element.addEventListener("click", (e) => { + let position = e.currentTarget.id; + e.preventDefault(); + if (startPosition == null) { + chooseFirstPosition(position); + } else { + chooseSecondPosition(position); } - ); + }); + } + ); }; \ No newline at end of file diff --git a/src/main/resources/static/public/js/index.js b/src/main/resources/static/public/js/index.js new file mode 100644 index 0000000000..15a690fe2c --- /dev/null +++ b/src/main/resources/static/public/js/index.js @@ -0,0 +1,39 @@ +window.onload = function () { + document.querySelector("#new").addEventListener("click", () => { + let gameName = prompt("게임 이름을 입력하세요."); + if (!gameName) { + alert("게임 이름을 입력하지 않으셨습니다."); + return; + } + fetch("http://localhost:8080/new", { + method: "POST", + body: JSON.stringify({ + gameName: gameName + }), + headers: {"Content-Type": "application/json"} + }) + .then(async function (response) { + return await response.json(); + }) + .then(data => { + let gameId = data["gameId"]; + window.location.href = `/game/${gameId}`; + }); + }); + + function showGames() { + fetch("http://localhost:8080/games") + .then(res => res.json()) + .then(games => { + const loadingDiv = document.querySelector("#loading-table > tbody"); + loadingDiv.innerHTML += generateGames(games, Object.keys(games["games"])); + }); + } + + function generateGames(games, keys) { + return keys.map(key => `${key}${games["games"][key]}`) + .join(""); + } + + showGames(); +}; \ No newline at end of file diff --git a/src/main/resources/templates/chess.hbs b/src/main/resources/templates/chess.hbs index 11b7a9abb7..09ad01358c 100644 --- a/src/main/resources/templates/chess.hbs +++ b/src/main/resources/templates/chess.hbs @@ -3,7 +3,7 @@ ♛Play Chess Game♚ - +
@@ -100,6 +100,9 @@
- + + \ No newline at end of file diff --git a/src/main/resources/templates/index.hbs b/src/main/resources/templates/index.hbs index f804b32259..d6f130b9d6 100644 --- a/src/main/resources/templates/index.hbs +++ b/src/main/resources/templates/index.hbs @@ -8,11 +8,25 @@

체스게임

- +
- + + + + + + + + + +
+ 게임 아이디 + + 게임 이름 +
+ \ No newline at end of file diff --git a/src/main/resources/templates/public/js/chess.js b/src/main/resources/templates/public/js/chess.js index 384e3dbe7e..cfc9cf7ba3 100644 --- a/src/main/resources/templates/public/js/chess.js +++ b/src/main/resources/templates/public/js/chess.js @@ -1,139 +1,139 @@ window.onload = function () { - const PIECES = { - BLACK_KING: ``, - BLACK_QUEEN: ``, - BLACK_ROOK: ``, - BLACK_BISHOP: ``, - BLACK_KNIGHT: ``, - BLACK_BLACK_PAWN: ``, - WHITE_KING: ``, - WHITE_QUEEN: ``, - WHITE_ROOK: ``, - WHITE_BISHOP: ``, - WHITE_KNIGHT: ``, - WHITE_WHITE_PAWN: ``, - }; - let startPosition = null; + const PIECES = { + BLACK_KING: ``, + BLACK_QUEEN: ``, + BLACK_ROOK: ``, + BLACK_BISHOP: ``, + BLACK_KNIGHT: ``, + BLACK_BLACK_PAWN: ``, + WHITE_KING: ``, + WHITE_QUEEN: ``, + WHITE_ROOK: ``, + WHITE_BISHOP: ``, + WHITE_KNIGHT: ``, + WHITE_WHITE_PAWN: ``, + }; + let startPosition = null; - async function getChessGame() { - const response = await fetch("http://localhost:4567/board"); - return await response.json(); - } - - function setBoard(board) { - document.querySelectorAll(".position").forEach(element => { - while (element.lastElementChild) { - element.removeChild(element.lastElementChild); - } - }); - Object.keys(board) - .filter(position => board[position]["pieceType"] !== "BLANK") - .forEach(position => { - const color = board[position]["color"]; - const pieceType = board[position]["pieceType"]; - document.getElementById(position) - .insertAdjacentHTML("beforeend", PIECES[`${color}_${pieceType}`]); - }); - } + async function getChessGame() { + const response = await fetch("http://localhost:4567/board"); + return await response.json(); + } - function setTurn(turn) { - document.getElementById("turn_box") - .innerHTML = '

' + turn["color"] + "의 턴입니다." + '

'; - } - - function setScore(score) { - document.getElementById("score") - .innerHTML = '

' + - "WHITE 팀의 점수는 " + score["WHITE"] + "점 입니다.\n" + - "BLACK 팀의 점수는 " + score["BLACK"] + "점 입니다." + - '

'; - } + function setBoard(board) { + document.querySelectorAll(".position").forEach(element => { + while (element.lastElementChild) { + element.removeChild(element.lastElementChild); + } + }); + Object.keys(board) + .filter(position => board[position]["pieceType"] !== "BLANK") + .forEach(position => { + const color = board[position]["color"]; + const pieceType = board[position]["pieceType"]; + document.getElementById(position) + .insertAdjacentHTML("beforeend", PIECES[`${color}_${pieceType}`]); + }); + } - (async function () { - const chessGame = await getChessGame(); - const board = chessGame["boardDto"]["board"]; - const turn = chessGame["turn"]; - const score = chessGame["score"]["scores"]; + function setTurn(turn) { + document.getElementById("turn_box") + .innerHTML = '

' + turn["color"] + "의 턴입니다." + '

'; + } - if (chessGame["normalStatus"] === false) { - alert("잘못된 명령입니다."); - return; - } - setBoard(board); - setTurn(turn); - setScore(score); - })(); + function setScore(score) { + document.getElementById("score") + .innerHTML = '

' + + "WHITE 팀의 점수는 " + score["WHITE"] + "점 입니다.\n" + + "BLACK 팀의 점수는 " + score["BLACK"] + "점 입니다." + + '

'; + } - function chooseFirstPosition(position) { - fetch(`http://localhost:4567/source?source=${position}`, {method: "POST"}) - .then(res => res.json()) - .then(data => { - startPosition = data.position; - console.log(data.normalStatus); - if (data.normalStatus === false) { - alert(data.exception); - startPosition = null; - return; - } - const positions = data.movable; - positions.forEach(position => { - document.getElementById(position) - .style - .backgroundColor = "rgba(255, 100, 0, 0.2)"; - }); + (async function () { + const chessGame = await getChessGame(); + const board = chessGame["boardDto"]["board"]; + const turn = chessGame["turn"]; + const score = chessGame["score"]["scores"]; - document.getElementById(position) - .style - .backgroundColor = "rgba(255, 200, 0, 0.2)"; - }); + if (chessGame["normalStatus"] === false) { + alert("잘못된 명령입니다."); + return; } + setBoard(board); + setTurn(turn); + setScore(score); + })(); - function chooseSecondPosition(position) { - fetch(`http://localhost:4567/destination?destination=${position}`, {method: "POST"}) - .then(res => res.json()) - .then(data => { - if (data.normalStatus === false) { - alert(data.exception); - return; - } - const source = startPosition; - const destination = data.position; - startPosition = null; + function chooseFirstPosition(position) { + fetch(`http://localhost:4567/source?source=${position}`, {method: "POST"}) + .then(res => res.json()) + .then(data => { + startPosition = data.position; + console.log(data.normalStatus); + if (data.normalStatus === false) { + alert(data.exception); + startPosition = null; + return; + } + const positions = data.movable; + positions.forEach(position => { + document.getElementById(position) + .style + .backgroundColor = "rgba(255, 100, 0, 0.2)"; + }); - if (source === destination) { - alert("이동을 취소합니다."); - } + document.getElementById(position) + .style + .backgroundColor = "rgba(255, 200, 0, 0.2)"; + }); + } - post_to_url("/board", {"source": source, "destination": destination}); - }); - } + function chooseSecondPosition(position) { + fetch(`http://localhost:4567/destination?destination=${position}`, {method: "POST"}) + .then(res => res.json()) + .then(data => { + if (data.normalStatus === false) { + alert(data.exception); + return; + } + const source = startPosition; + const destination = data.position; + startPosition = null; - document.querySelectorAll(".position").forEach( - element => { - element.addEventListener("click", (e) => { - let position = e.currentTarget.id; - e.preventDefault(); - if (startPosition == null) { - chooseFirstPosition(position); - } else { - chooseSecondPosition(position); - } - }); + if (source === destination) { + alert("이동을 취소합니다."); } - ); - function post_to_url(path, params) { - let form = document.createElement("form"); - form.setAttribute("method", "post"); - form.setAttribute("action", path); - for (let key in params) { - let hiddenField = document.createElement("input"); - hiddenField.setAttribute("type", "hidden"); - hiddenField.setAttribute("name", key); - hiddenField.setAttribute("value", params[key]); - form.appendChild(hiddenField); + post_to_url("/board", {"source": source, "destination": destination}); + }); + } + + document.querySelectorAll(".position").forEach( + element => { + element.addEventListener("click", (e) => { + let position = e.currentTarget.id; + e.preventDefault(); + if (startPosition == null) { + chooseFirstPosition(position); + } else { + chooseSecondPosition(position); } - document.body.appendChild(form); - form.submit(); + }); + } + ); + + function post_to_url(path, params) { + let form = document.createElement("form"); + form.setAttribute("method", "post"); + form.setAttribute("action", path); + for (let key in params) { + let hiddenField = document.createElement("input"); + hiddenField.setAttribute("type", "hidden"); + hiddenField.setAttribute("name", key); + hiddenField.setAttribute("value", params[key]); + form.appendChild(hiddenField); } + document.body.appendChild(form); + form.submit(); + } }; \ No newline at end of file diff --git a/src/main/resources/templates/result.hbs b/src/main/resources/templates/result.hbs index 2506a1d37d..b0dd35c68f 100644 --- a/src/main/resources/templates/result.hbs +++ b/src/main/resources/templates/result.hbs @@ -3,14 +3,14 @@ Chess Game Result - +

{{winner}}팀 승리!

\ No newline at end of file diff --git a/src/test/java/wooteco/chess/entity/GameRepositoryTest.java b/src/test/java/wooteco/chess/entity/GameRepositoryTest.java new file mode 100644 index 0000000000..25e82aa4ef --- /dev/null +++ b/src/test/java/wooteco/chess/entity/GameRepositoryTest.java @@ -0,0 +1,82 @@ +package wooteco.chess.entity; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(SpringExtension.class) +@DataJdbcTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +class GameRepositoryTest { + + private final String firstGameName = "first game"; + + @Autowired + private GameRepository gameRepository; + + @DisplayName("save 새 게임 시작시 게임정보 저장 테스트") + @Test + void save_normal_test() { + Game game = gameRepository.save(new Game(firstGameName, true)); + + assertThat(game.getId()).isEqualTo(1); + assertThat(game.getName()).isEqualTo(firstGameName); + assertThat(game.getCanContinue()).isEqualTo(true); + } + + @DisplayName("게임 목록 중 진행중인 게임 조회 기능 구현") + @Test + void findAvailableGames_test() { + Game firstGame = gameRepository.save(new Game(firstGameName, true)); + Game secondGame = gameRepository.save(new Game("secondGameName", true)); + Game thirdGame = gameRepository.save(new Game("thirdGameName", false)); + + List games = gameRepository.findAvailableGames(); + + assertThat(games).contains(firstGame, secondGame); + assertThat(games).doesNotContain(thirdGame); + } + + @DisplayName("이미 저장되어있는 게임에 canContinue를 false로 변경 확인") + @Test + void save_update_can_continue_column() { + gameRepository.save(new Game(firstGameName, true)); + + Game foundGame = gameRepository.findById(1L).get(); + + Game actualGame = gameRepository.save(new Game(foundGame.getId(), foundGame.getName(), false)); + + assertThat(actualGame.getCanContinue()).isEqualTo(false); + } + + @DisplayName("게임 선택 시 해당하는 히스토리 조회") + @Test + void getHistories_history_from_specific_game() { + Game firstGame = gameRepository.save(new Game(firstGameName, true)); + Game secondGame = gameRepository.save(new Game("secondGameName", true)); + History firstHistory = new History("a2", "a4"); + History secondHistory = new History("b2", "b4"); + History thirdHistory = new History("a7", "a5"); + firstGame.addHistory(firstHistory); + secondGame.addHistory(secondHistory); + firstGame.addHistory(thirdHistory); + + Game persistFirstGame = gameRepository.save(firstGame); + Game persistSecondGame = gameRepository.save(secondGame); + + Set firstHistories = persistFirstGame.getHistories(); + Set secondHistories = persistSecondGame.getHistories(); + + assertThat(firstHistories).contains(firstHistory, thirdHistory); + assertThat(secondHistories).contains(secondHistory); + } +} \ No newline at end of file diff --git a/src/test/resouces/application.properties b/src/test/resouces/application.properties new file mode 100644 index 0000000000..bec9d9b83d --- /dev/null +++ b/src/test/resouces/application.properties @@ -0,0 +1,3 @@ +spring.h2.console.enabled=true +logging.level.org.springframework.jdbc=TRACE +spring.datasource.initialization-mode=ALWAYS