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

[3, 4단계 - 체스] 제이(이재윤) 미션 제출합니다. #530

Merged
merged 45 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
9c2396a
docs: 기능 구현 목록 수정
sosow0212 Mar 19, 2023
6cb22ba
refactor: 커맨드를 일급 컬렉션으로 변경
sosow0212 Mar 19, 2023
832bd00
refactor: 사용하지 않는 상수 제거
sosow0212 Mar 19, 2023
aeebb02
refactor: 값이 없는 경우 예외 메시지 출력하도록 변경
sosow0212 Mar 19, 2023
9b4442a
refactor: 조건문을 더욱 직관적이게 변경
sosow0212 Mar 19, 2023
d2c2a6e
test: Command에서 성공하는 경우의 테스트도 추가
sosow0212 Mar 19, 2023
48824eb
style: 개행 맞춤
sosow0212 Mar 19, 2023
11282d7
feat: 체스의 말이 점수를 가지고 있게 리팩토링 및 Board에서 팀 별로 점수 반환
sosow0212 Mar 19, 2023
700da6f
refactor: 체스 말에서 폰이 같은 Column에 있을 경우 0.5점을 반환하도록 리팩토링 진행
sosow0212 Mar 19, 2023
2a3a624
test: 3단계 요구사항에 나온 테스트용 맵을 통해 점수 계산 테스트 추가
sosow0212 Mar 19, 2023
b64a004
feat: King이 죽으면 게임이 종료하는 기능 추가
sosow0212 Mar 19, 2023
3f8d963
feat: 점수 출력 및 승패 출력을 해주는 기능 추가
sosow0212 Mar 20, 2023
6ff9da9
docs: 기능 구현 목록 수정
sosow0212 Mar 20, 2023
330b809
refactor: 킹이 잡혀서 종료된 경우 추가
sosow0212 Mar 20, 2023
3d77a16
refactor: 상수 처리 및 주석 제거
sosow0212 Mar 20, 2023
051ee0e
style: 필요 없는 개행 삭제
sosow0212 Mar 20, 2023
063af9f
docs: DB설계 내용 작성
sosow0212 Mar 20, 2023
7a719bc
feat: 체스 보드를 DB에 저장하는 기능 추가
sosow0212 Mar 21, 2023
62577bf
feat: 체스 게임 저장 기능 구현 (리팩토링 전)
sosow0212 Mar 21, 2023
86f0102
style: 패키지명 변경
sosow0212 Mar 21, 2023
f222984
fix: 게임을 불러올 때 Rook이 Place로 생성되는 오류 해결
sosow0212 Mar 21, 2023
41ce6c7
refactor: 리네이밍 및 컨트롤러 구조 변경
sosow0212 Mar 21, 2023
0db7ea5
feat: 체스 게임의 턴을 나타내는 기능 추가
sosow0212 Mar 21, 2023
189dd1b
feat: 저장된 체스 게임을 할 것인지 새로운 게임을 할 것인지 선택하는 기능 추가
sosow0212 Mar 21, 2023
dcdbb80
refactor: Pawn의 점수 계산 로직 변경
sosow0212 Mar 21, 2023
5f87010
style: 디렉토리 구조 변경
sosow0212 Mar 21, 2023
14ae3ed
del: 미니 미션 제거
sosow0212 Mar 21, 2023
028bbc7
test: 테스트하지 못한 메서드에 대해 테스트 추가
sosow0212 Mar 21, 2023
72e6bf2
feat: 게임 종료시 문구 출력 기능 추가
sosow0212 Mar 21, 2023
f5c2788
style: 개행 통일 및 안 쓰는 공백 제거
sosow0212 Mar 21, 2023
60513f8
refactor: 컨트롤러 코드 리팩토링
sosow0212 Mar 21, 2023
0299e0c
refactor: 클래스 네이밍 변경
sosow0212 Mar 21, 2023
9f591d6
refactor: 메서드명 변경
sosow0212 Mar 21, 2023
454c09d
docs: 기능 구현 목록 수정
sosow0212 Mar 21, 2023
00c90d1
refactor: DB에 저장될 때 Piece, Position을 문자열로 압축하도록 변경
sosow0212 Mar 22, 2023
cea5745
refactor: 클래스 네이밍 통일
sosow0212 Mar 22, 2023
b8c9fd9
refactor: DB에 체스판을 저장하거나 가져올 때 문자열로 파싱해주는 기능 추가
sosow0212 Mar 22, 2023
4eb9c8d
refactor: DB 테이블 변경함에 따라 코드 리팩토링 진행
sosow0212 Mar 22, 2023
b0f58da
docs: 테이블 DDL 추가
sosow0212 Mar 22, 2023
6a23cba
refactor: 상수 추출
sosow0212 Mar 22, 2023
5a144d4
refactor: View <-> Controller <-> Dao 통신을 Dto를 통해서 하도록 리팩토링 진행
sosow0212 Mar 22, 2023
6b0a221
refactor: 불필요한 if문 제거
sosow0212 Mar 22, 2023
5c6b8fc
refactor: 코드 메서드 참조로 변경
sosow0212 Mar 22, 2023
262eb61
refactor: Dto에서 String, Integer 같은 클래스만 전달하도록 리팩토링
sosow0212 Mar 22, 2023
1073412
refactor: OutputView에서 status 출력문 추가
sosow0212 Mar 22, 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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
- [x] 초기 체스판을 생성한다.
- [x] 자기 위치로는 움직일 수 없다.
- [x] 경로 내 장애물이 있는 지 검증한다.
- [x] 게임에서 남아있는 말에 대한 점수를 구해야한다.

- [x] King이 잡히는 경우 게임에서 진다. (게임 종료)
- [x] `status` 명령어를 입력하면 각 진영의 점수를 출력하고 어느 진영이 이겼는지 결과를 볼 수 있어야한다. (게임 종료)
- [x] `end` 명령어를 입력하면 프로그램이 종료한다. (프로그램 종료)
- [x] 초기 게임 상태 명령어를 받아서 체스 게임을 새로 시작할지 혹은 기존 게임을 불러올지 정할 수 있다.

### 기물
- [x] 체스판을 구성하는 요소이다.
Expand Down Expand Up @@ -45,3 +51,13 @@
### 출력
- [x] 게임 시작 문구를 출력한다.
- [x] 체스판 현황을 출력한다.

### DB
- DB 계획도
- Room (room_id, game_id, user1, user2) --> 추가 미션 예정
- Game (game_id, board_id) --> 추가 미션 예정
- board (board_id, position(String), piece(String), isLowerTeamTurn) --> isLowerTeamTurn은 추가 미션 때 Game 테이블로 옮길 예정입니다.

Choose a reason for hiding this comment

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

현재는 BOARD_ID를 통해 단일 저장만 지원하도록 로직 작성해주셨고,
이후 추가 미션으로 나머지 테이블에 대해 구현을 수행하는 것으로 확인했습니다. 👍

다만 테이블의 구조 변경이 필요해 보이므로, 이를 수행한 뒤 이 부분도 변경해주시길 바랍니다.

Copy link
Author

Choose a reason for hiding this comment

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

@include42

카프카, 안녕하세요? 추가로 질문이 있습니다 !

개인적으로 DB로 데이터를 넣고, 받아오는 과정은 매우 중요하다고 생각합니다.
(만약 협업을 가정한다고 했을 때, 동료 개발자가 실수로 도메인 메서드를 DAO와 관련된 부분에서 실행하면 값이 바뀔 수도 있기 때문입니다!)

따라서 Controller <-> Service <-> DAO 에서 DTO를 적용해보고 싶은데,
이런 경우 DTO에서 BoardUtil에서 하는 역할을 불러서 수행을 시키고 보내는게 맞을까요?

카프카의 생각은 어떤가요?? DTO의 책임은 어느정도까지인지 감이 잡히질 않아서 질문 남깁니다 :)

Choose a reason for hiding this comment

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

안녕하세요 제이!
말씀해주신 이유와 같은 이유로, 저도 DTO가 각 레이어간 통신에 필요하다고 생각합니다.

  • 우선 View <-> Controller <-> Service 간에 적용해보면 좋을 것으로 보입니다.

그리고 BoardUtil에서 하는 역할을 불러서 수행시킨다는 것은, Board를 가공하는 과정을 DTO가 책임져도 된다는 의미의 질문일까요?

저는 DTO의 책임은 값을 저장하고, 저장된 값을 전달한다 에 있다고 생각합니다. 그렇기 때문에 이상적인 DTO라면 생성자와 getter만 있어도 충분하겠지요.
다만 위 원칙대로라면 별도의 Converter 클래스가 Domain <-> DTO를 수행해야 하는데, 이러면서 클래스가 너무 많아져 관리가 어려울 경우 DTO에 정적 팩토리 메소드로 도메인을 인자로 받아 생성하는 정도는 허용하기도 합니다.
그 외의 연산 로직은 DTO에 필요할 것 같지는 않네요. 예를 들어 BoardUtil의 메소드들이 DTO에 있는 것은, 책임을 넘어서는 구조라고 생각이 됩니다. (정적 팩토리 메소드에서 호출해주는 정도는 가능하겠지만, 일단 DTO가 너무 복잡해지는 것은 좋지 않다고 생각합니다)

현재의 상황에서 제일 단순한 해결법은, 서비스 내에서 BoardUtil을 통해 필요한 값을 만들어주고 해당 값을 DTO에 넣어서 컨트롤러에 전달해주는 방법일 것 같습니다. 그러면 Controller는 해당 DTO를 다시 View에 넘기고요.

Copy link
Author

Choose a reason for hiding this comment

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

@include42
그렇군요! 감사합니다 :)
말씀해주신 내용을 바탕으로 추가로 커밋하였습니다!





6 changes: 5 additions & 1 deletion src/main/java/chess/Application.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package chess;

import chess.controller.ChessGameController;
import chess.service.BoardService;
import chess.view.InputView;
import chess.view.OutputView;
import chess.view.ResultView;

public class Application {

public static void main(String[] args) {
ChessGameController chessGameController = new ChessGameController(
new InputView(),
new OutputView()
new OutputView(),
new ResultView(),
new BoardService()
);

chessGameController.run();
Expand Down
134 changes: 105 additions & 29 deletions src/main/java/chess/controller/ChessGameController.java
Original file line number Diff line number Diff line change
@@ -1,66 +1,142 @@
package chess.controller;

import chess.domain.commnad.Command;
import chess.domain.commnad.LoadGameCommand;
import chess.domain.game.ChessGame;
import chess.factory.BoardFactory;
import chess.service.BoardService;
import chess.view.InputView;
import chess.view.OutputView;
import java.util.List;
import chess.view.ResultView;

public class ChessGameController {

private static final String START_COMMAND = "start";
private static final String MOVE_COMMAND = "move";
private static final String END_COMMAND = "end";
private static final int COMMAND_INDEX = 0;
private static final int SELECTED_PIECE = 1;
private static final int DESTINATION = 2;
private static final int BOARD_ID = 1;

private final InputView inputView;
private final OutputView outputView;
private final ResultView resultView;
private final BoardService boardService;

public ChessGameController(final InputView inputView, final OutputView outputView) {
public ChessGameController(final InputView inputView,
final OutputView outputView,
final ResultView resultView,
final BoardService boardService) {
this.inputView = inputView;
this.outputView = outputView;
this.resultView = resultView;
this.boardService = boardService;
}

public void run() {
ChessGame chessGame = new ChessGame(BoardFactory.createBoard());
LoadGameCommand loadGameCommand = inputView.readStatusOfGame();
ChessGame chessGame = loadGame(loadGameCommand);

outputView.printStartMessage();
playChess(chessGame);

List<String> inputCommand = inputView.readGameCommand();
resultView.printGameEnd();
}

private ChessGame loadGame(final LoadGameCommand loadCommand) {
if (loadCommand.isSavedGame()) {
ChessGame chessGame = new ChessGame(boardService.findById(BOARD_ID), boardService.isLowerTeamTurnByBoardId(BOARD_ID));
outputView.printBoard(chessGame.getBoard());
return chessGame;
}

Choose a reason for hiding this comment

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

나중에 room 을 구현하게 되면 여기에서는 room에 포함되는 boardId로만 대체해줘도 로딩에 문제가 없겠네요.
로드하는 부분의 구조를 잘 짜주셨습니다.


playChess(chessGame, inputCommand);
return new ChessGame(BoardFactory.createBoard(), true);
}

private void playChess(ChessGame chessGame, List<String> inputCommand) {
while (isNotEnd(inputCommand)) {
try {
chessGame = createNewChessGame(chessGame, inputCommand);
tryChessMove(chessGame, inputCommand);
outputView.printBoard(chessGame.getBoard());
inputCommand = inputView.readGameCommand();
} catch (IllegalArgumentException exception) {
System.out.println(exception.getMessage());
inputCommand = inputView.readGameCommand();

private void playChess(ChessGame chessGame) {
Command command = inputView.readGameCommand();

while (!isGameEndCase(chessGame, command)) {
chessGame = checkCreateNewGame(chessGame, command);

checkMovePiece(chessGame, command);
outputView.printBoard(chessGame.getBoard());

if (isGameDone(chessGame)) {
break;
}

command = inputView.readGameCommand();
}
}

private boolean isNotEnd(final List<String> inputCommand) {
return !inputCommand.get(COMMAND_INDEX).equals(END_COMMAND);
private boolean isGameEndCase(final ChessGame chessGame, final Command command) {
if (isGameEnd(chessGame, command)) {
resultView.printGameEndWithSaving();
boardService.delete(BOARD_ID);
boardService.save(BOARD_ID, chessGame.getBoard(), chessGame.isLowerTeamTurn());
return true;
}

return false;
}

private boolean isGameEnd(final ChessGame chessGame, final Command command) {
if (isCommandStatus(chessGame, command) || command.isGameStop()) {
return true;
}

return false;

Choose a reason for hiding this comment

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

이부분은 별도의 로직 처리가 없다면 (isCommandStatus(chessGame, command) || command.isGameStop())을 바로 반환해줘도 괜찮겠네요!
물론 if문으로 쓸 경우 확장성이 더 좋고 의미가 명확해지므로, 제이가 생각하는 더 좋은 방향을 결정해주세요 😄

Copy link
Author

Choose a reason for hiding this comment

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

이 부분은 전 리뷰어분께서도 말씀해주셨는데, 습관이 돼서 자꾸 인지를 못하네요 ㅠㅠ

굳이 if문을 쓰지 않아도 이해하는데 문제가 없기 때문에 저도 카프카와 동의합니다!

꼼꼼하게 봐주셔서 감사합니다🙇🏻‍♂️

}

private void tryChessMove(final ChessGame chessGame, final List<String> inputCommand) {
if (inputCommand.get(COMMAND_INDEX).startsWith(MOVE_COMMAND)) {
chessGame.move(inputCommand.get(SELECTED_PIECE), inputCommand.get(DESTINATION));
private boolean isCommandStatus(final ChessGame chessGame, final Command command) {
if (command.isStatus()) {
resultView.printScore(chessGame.calculateScoreOfUpperTeam(), chessGame.calculateScoreOfLowerTeam());
resultView.printWinner(chessGame.calculateScoreOfUpperTeam(),
chessGame.calculateScoreOfLowerTeam());
return true;
}

return false;
}

private ChessGame createNewChessGame(ChessGame chessGame, final List<String> inputCommand) {
if (inputCommand.get(COMMAND_INDEX).equals(START_COMMAND)) {
chessGame = new ChessGame(BoardFactory.createBoard());
private ChessGame checkCreateNewGame(final ChessGame chessGame, final Command command) {
if (command.isCreateNewGame()) {
chessGame.initGame();
}

return chessGame;
}

private boolean isGameDone(final ChessGame chessGame) {
if (isKingDead(chessGame)) {
resultView.printGameEndWithDeleting();
boardService.delete(BOARD_ID);
return true;
}

return false;
}

private boolean isKingDead(final ChessGame chessGame) {
if (chessGame.isKingDead() && chessGame.isUpperTeamWin()) {
resultView.printWinnerIsUpperTeam();
return true;
}

if (chessGame.isKingDead() && !chessGame.isUpperTeamWin()) {
resultView.printWinnerIsLowerTeam();
return true;
}

return false;
}

private void checkMovePiece(final ChessGame chessGame, final Command command) {
if (!command.isMove()) {
return;
}

try {
chessGame.move(command.findSelectedPiece(), command.findDestination());
} catch (IllegalArgumentException exception) {
System.out.println(exception.getMessage());
}
}
}
14 changes: 14 additions & 0 deletions src/main/java/chess/dao/board/BoardDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package chess.dao.board;

import java.util.Map;

public interface BoardDao {

Choose a reason for hiding this comment

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

혹시 BoardDao와 BoardDaoImpl을 나눈 이유가 있을까요?
실제로 개발 현장에서 많이 쓰는 패턴이기는 하나, 사용에 명확한 이유가 없다면 하나로 합쳐도 괜찮아 보입니다.


void save(final int boardId, final Map<String, String> board, final boolean isLowerTeamTurn);

Map<String, String> findById(final int boardId);

boolean isLowerTeamTurnByBoardId(final int boardId);

void remove(int boardId);
}
105 changes: 105 additions & 0 deletions src/main/java/chess/dao/board/BoardDaoImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package chess.dao.board;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class BoardDaoImpl implements BoardDao {

Choose a reason for hiding this comment

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

로컬에 DB를 올려서 테스트를 수행해 보았는데, 현재의 테이블 구조에 문제가 있어 변경이 필요해 보입니다.
현재 테이블에 pk(primary key) 설정은 수행하지 않으신거죠?
확인해보니 저장할때 아래와 같이 저장을 진행하더군요.

  • id, 포지션, 기물, 턴 순으로 저장
  • 이를 전체 기물 수만큼 저장하게 됨

image

이러한 구조는 적절하지 않습니다. 제가 생각하는 그 이유는 다음과 같습니다.

  • id는 고유값으로 설정하는 것이 좋습니다. db에 요청을 보낼 때, 아이디를 통해 각각의 값을 구분하기 때문입니다. 현재 구조는 비유하자면, 대한민국 국민을 나이별로 묶어 같은 주민번호를 사용하도록 한 것과 같습니다. 이 경우 유사한 데이터간의 구분이 어려워집니다.
  • board라는 테이블의 구조를 생각할 때, 하나의 데이터는 하나의 보드의 정보를 저장해야 합니다. 현재 구조는 하나의 보드 정보 저장을 위해 board 64개를 db에 삽입하게 됩니다.
  • 도중에 에러가 나 연산이 중단된다면 문제가 발생할 수 있습니다. (원자성에 대한 문제인데, 일단 그럴 수 있다라고만 알아두셔도 지금은 충분합니다)

아직 database에 대해 학습하신 내용이 적어서, 충분히 할 수 있는 실수입니다.
그러나 해당 설계로 프로젝트 진행할 경우 이후의 추가 미션 진행에도 어려움이 있을 것으로 보입니다.
이번에는 테이블의 수정만 진행해 주시고, 추후 레벨2 진행하는 과정에서 db 학습을 이어나가셔도 충분할 것으로 생각됩니다.

Choose a reason for hiding this comment

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

저는 아래와 같은 개선이 필요하다고 생각해요.

  • 보드당 id는 1개만 사용(하나의 보드 정보 저장 시 하나의 값으로 저장)
  • position과 piece 대신, 문자열 1개로 압축(길이가 64인 문자열이 되겠지요)한 필드 정보를 저장
  • Board <-> String을 수행할 util 클래스를 구현하고, 변환 책임은 그쪽으로 옮겨둠

물론 더 복잡한 구조로 구현할수도 있겠으나, 이 경우 오버엔지니어링이 될 위험이 있습니다.
또한 이번 미션은 DB를 프로젝트에 적용해보는 것이 목표이므로, 최대한 간단하게 테이블 정책을 잡는 것이 학습 목표에 맞다고 생각하여 조언 드렸습니다.
만약 위의 방향보다 더 좋으면서 id의 고유성을 보장하는 방법이 있다면, 해당 방법을 바탕으로 리팩토링 진행하셔도 괜찮습니다.

해당 내용 수행 후, 테이블 생성시 사용된 DDL을 코멘트로 남겨주시면 참고해서 리뷰 진행하겠습니다.

Copy link
Author

@sosow0212 sosow0212 Mar 22, 2023

Choose a reason for hiding this comment

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

문자열 1개로 압출하는 방법이 있었군요..! 왜 이 생각을 못했을까요 ㅠㅠ

저는 기존에는 64개(Position, Piece)를 모두 저장해야한다는 생각 때문에, 기본키를 누가 가져야하는지에 대해서 고민이 많았습니다.

board_id가 가진다면 기본키는 중복이 안되기에 position, piece와 함께 저장이 모두 안되기 때문에 기본키를 없애거나, board_id와 position을 기본키로 설정하는 방식으로 진행했는데, 좋은 방법 하나 배워갑니다!

감사합니다 :)

테이블 생성 DDL은 다음과 같습니다.

CREATE TABLE `chess`.`board` (
  `board_id` INT NOT NULL,
  `position` VARCHAR(300) NOT NULL,
  `piece` VARCHAR(300) NOT NULL,
  `isLowerTeamTurn` TINYINT NOT NULL,
  PRIMARY KEY (`board_id`));


private static final String SERVER = "localhost:13306";
private static final String DATABASE = "chess";
private static final String OPTION = "?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "root";

public Connection getConnection() {
try {
return DriverManager.getConnection("jdbc:mysql://" + SERVER + "/" + DATABASE + OPTION, USERNAME, PASSWORD);
} catch (final SQLException e) {
System.err.println("DB 연결 오류:" + e.getMessage());
e.printStackTrace();
return null;
}
}

@Override
public void save(final int boardId, final Map<String, String> board, final boolean isLowerTeamTurn) {
final String query = "INSERT INTO board (board_id, position, piece, isLowerTeamTurn) VALUES (?, ?, ?, ?)";

try (final PreparedStatement preparedStatement = getConnection().prepareStatement(query)) {

for (final Entry<String, String> boardEntry : board.entrySet()) {
final String position = boardEntry.getKey();
final String piece = boardEntry.getValue();

preparedStatement.setInt(1, boardId);
preparedStatement.setString(2, position);
preparedStatement.setString(3, piece);
preparedStatement.setBoolean(4, isLowerTeamTurn);
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("board 저장 실패");
}
}

@Override
public Map<String, String> findById(final int boardId) {
final String query = "SELECT position, piece FROM board WHERE board_id = ?";
final Map<String, String> board = new HashMap<>();
try (final var connection = getConnection();
final var preparedStatement = connection.prepareStatement(query)) {

preparedStatement.setString(1, String.valueOf(boardId));
ResultSet result = preparedStatement.executeQuery();

while (result.next()) {
board.put(result.getString("position"), result.getString("piece"));
}
} catch (SQLException e) {
e.printStackTrace();
}

return board;
}

@Override
public boolean isLowerTeamTurnByBoardId(final int boardId) {
final String query = "SELECT isLowerTeamTurn FROM board WHERE board_id = ?";

try (final var connection = getConnection();
final var preparedStatement = connection.prepareStatement(query)) {

preparedStatement.setString(1, String.valueOf(boardId));

final ResultSet result = preparedStatement.executeQuery();

while (result.next()) {
return result.getBoolean("isLowerTeamTurn");
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}

@Override
public void remove(final int boardId) {
final String query = "DELETE FROM board WHERE board_id = ?";

try (final var connection = getConnection();
final var preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, String.valueOf(boardId));
preparedStatement.executeUpdate();
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
}