Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
6278db2
test(Palace): ꢁ성 ν…ŒμŠ€νŠΈ μž‘μ„±
frombunny Apr 7, 2026
4cf8291
feat(Palace): ꢁ성 νŒμ • 둜직 κ΅¬ν˜„
frombunny Apr 7, 2026
6e60e02
test(Palace): ꢁ성 μ—¬λΆ€ λ°˜ν™˜ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
2c0427f
feat(Palace): 전체 ꢁ성 μ—¬λΆ€ λ°˜ν™˜ 둜직 μž‘μ„±
frombunny Apr 7, 2026
01cdf1b
test(MoveStrategy): μ‘Έ/병 ꢁ성 λ‚΄ 이동 ν…ŒμŠ€νŠΈ μž‘μ„±
frombunny Apr 7, 2026
8b5d5ec
feat(MoveStrategy): μ‘Έ/병 ꢁ성 λ‚΄ 이동 둜직 μž‘μ„±
frombunny Apr 7, 2026
65a3b8c
test(MoveStrategy): ꢁ/사 ꢁ성 λ‚΄ 이동 ν…ŒμŠ€νŠΈ
frombunny Apr 7, 2026
7255106
feat(MoveStrategy): ꢁ/사 ꢁ성 λ‚΄ 이동 둜직 μž‘μ„±
frombunny Apr 7, 2026
a042190
test(MoveStrategy): μ°¨/포 ꢁ성 λ‚΄ 이동 ν…ŒμŠ€νŠΈ μž‘μ„±
frombunny Apr 7, 2026
b339224
feat(MoveStrategy): μ°¨/포 ꢁ성 λ‚΄ 이동 둜직 μž‘μ„±
frombunny Apr 7, 2026
381c6ba
test(MoveStrategy): ꢁ성 둜직 ν…ŒμŠ€νŠΈλͺ… κ°œμ„ 
frombunny Apr 7, 2026
904384c
test(MoveStrategy): ꢁ성 둜직 μ‘Έ/병 μ˜ˆμ™Έ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
2cf87fd
feat(MoveStrategy): ꢁ성 둜직 μ‘Έ/병 μ˜ˆμ™Έ 처리 μΆ”κ°€
frombunny Apr 7, 2026
8b2d866
test(Palace): ꢁ성 쀑앙 μ—¬λΆ€ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
1f90bb1
feat(Palace): ꢁ성 쀑앙 μ—¬λΆ€ λ°˜ν™˜ 둜직 μž‘μ„±
frombunny Apr 7, 2026
dc6802d
test(MoveStrategy): ꢁ,사,μ‘Έ/병 ꢁ성 이동 μ˜ˆμ™Έ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
24398fa
feat(MoveStrategy): ꢁ,사,μ‘Έ/병 ꢁ성 이동 μ˜ˆμ™Έ 처리 μΆ”κ°€
frombunny Apr 7, 2026
39923da
test(MoveStrategy): ꢁ성 이동 둜직 ν…ŒμŠ€νŠΈλͺ… κ°œμ„ 
frombunny Apr 7, 2026
0be6dac
test(MoveStrategy): 포 ꢁ성 이동 μ˜ˆμ™Έ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
51b9556
feat(MoveStrategy): μ°¨/포 ꢁ성 이동 μ˜ˆμ™Έ 둜직 μž‘μ„±
frombunny Apr 7, 2026
bc5c954
test(Direction): 직선 λ°©ν–₯ νŒμ • ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
b1fea2b
feat(Direction): 직선 λ°©ν–₯ νŒμ • 둜직 κ΅¬ν˜„
frombunny Apr 7, 2026
21a517b
test(Palace): ꢁ성 이동 κ°€λŠ₯ 경둜 λ°˜ν™˜ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 7, 2026
84a331d
feat(Palace): ꢁ성 이동 κ°€λŠ₯ 경둜 λ°˜ν™˜ κΈ°λŠ₯ μΆ”κ°€
frombunny Apr 7, 2026
9fba4ff
refactor(MoveStrategy): ꢁ성 이동 κ°€λŠ₯ 경둜λ₯Ό Palaceκ°€ νŒλ‹¨ν•˜λ„λ‘ μœ„μž„
frombunny Apr 7, 2026
acf1053
test(Piece): κΈ°λ¬Ό νƒ€μž… λ°˜ν™˜ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 8, 2026
3b2fd5d
refactor(Piece): ꢁ μ—¬λΆ€ λ°˜ν™˜μ„ Pieceμ—κ²Œ μœ„μž„
frombunny Apr 8, 2026
b2fc894
feat(Data): 초기 ν…Œμ΄λΈ” μŠ€ν‚€λ§ˆ 생성
frombunny Apr 8, 2026
2edf16f
chore: DB κ΄€λ ¨ μ˜μ‘΄μ„± μΆ”κ°€
frombunny Apr 10, 2026
4760bab
feat(db): TransactionManager μž‘μ„±
frombunny Apr 10, 2026
96e082e
feat(Board): Board에 μ •μ νŒ©ν† λ¦¬λ©”μ„œλ“œ λ„μž…
frombunny Apr 10, 2026
50547ba
feat(dao): PieceDao μž‘μ„±
frombunny Apr 10, 2026
ada1c4c
feat(dao): BoardDao μž‘μ„±
frombunny Apr 10, 2026
a8e2db8
feat(repository): BoardRepository μž‘μ„±
frombunny Apr 10, 2026
4d62e04
chore(SQL): sqlλ¬Έ μˆ˜μ •
frombunny Apr 10, 2026
6ea62fb
feat(Controller): DB μ„€μ • μ—°κ²°
frombunny Apr 10, 2026
dff9109
refactor(Piece): Piece 내에 isGeneral ν•¨μˆ˜ 제거
frombunny Apr 10, 2026
b51395e
refactor(MoveStrategy): 쀑간 상속 클래슀 제거
frombunny Apr 10, 2026
13ea920
fix(Board): κ²Œμž„ μ’…λ£Œ μƒνƒœ νŒμ • 였λ₯˜ μˆ˜μ •
frombunny Apr 10, 2026
7e5c554
refactor(MoveStrategy): μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ„ μ–Έ 제거
frombunny Apr 10, 2026
e8966f5
test(MoveStrategy): μ „λž΅ λ¦¬νŒ©ν† λ§μ— λ”°λ₯Έ ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 10, 2026
ee2e010
feat(Piece): 점수 κΈ°λŠ₯ μΆ”κ°€
frombunny Apr 10, 2026
ae1aa9a
refactor: 컨트둀러 μ±…μž„ 뢄리
frombunny Apr 10, 2026
9323c36
fix(db): μŠ€ν‚€λ§ˆ 뢈일치 μˆ˜μ •
frombunny Apr 10, 2026
f3b90d3
test(db): DB ν…ŒμŠ€νŠΈ μΆ”κ°€
frombunny Apr 10, 2026
0a22c7b
feat(Board): μž₯기판 λͺ©λ‘ 좜λ ₯ κ΅¬ν˜„
frombunny Apr 10, 2026
8e3360f
fix(MoveStrategy): 포 이동 μ œμ•½ μˆ˜μ •
frombunny Apr 10, 2026
d55e7df
chore: μ’…λ£Œλœ κ²Œμž„μ€ λͺ©λ‘μ— 좜λ ₯ν•˜μ§€ μ•Šλ„λ‘ μˆ˜μ •
frombunny Apr 10, 2026
ced9270
fix(repository): μž₯기판 쑰회 μ‹œ, idλ₯Ό ν• λ‹Ήν•˜λ„λ‘ μˆ˜μ •
frombunny Apr 10, 2026
f8bb9d0
refactor: νŠΈλžœμž­μ…˜ 흐름을 λͺ…ν™•νžˆ λ“œλŸ¬λ‚΄λ„λ‘ TransactionManager ꡬ쑰 κ°œμ„ 
frombunny Apr 13, 2026
db4d1df
refactor(db): BoardDao λ©”μ„œλ“œ μΆ”μΆœ
frombunny Apr 13, 2026
d3f9819
refactor(PathGenerator): PathGenerator ν΄λž˜μŠ€λ“€μ„ 객체둜 λ³€κ²½
frombunny Apr 13, 2026
688ac17
refactor(PathInfos): List<PathInfo> 래퍼 클래슀 λ„μž…
frombunny Apr 13, 2026
42b00e7
refactor: μ‚¬μš©λ˜μ§€ μ•ŠλŠ” μ„ μ–Έ 제거
frombunny Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ repositories {
}

dependencies {
implementation 'com.zaxxer:HikariCP:6.0.0'
implementation 'com.h2database:h2:2.2.224'

testImplementation platform('org.junit:junit-bom:5.11.4')
testImplementation platform('org.assertj:assertj-bom:3.27.3')
testImplementation('org.junit.jupiter:junit-jupiter')
Expand Down
66 changes: 59 additions & 7 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,71 @@
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import controller.GameController;
import data.BoardDto;
import data.BoardRepository;
import data.TransactionManager;
import domain.board.Board;
import domain.board.BoardInitializer;
import domain.piece.Camp;
import view.InputView;
import view.OutputView;

import java.util.List;

public class Application {
public static void main(String[] args) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

λ©”μ„œλ“œκ°€ λ„ˆλ¬΄ κΉλ‹ˆλ‹€~

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

μ΄ˆκΈ°μ— step2 λΈŒλžœμΉ˜μ—μ„œ μž‘μ—…ν–ˆμ–΄μ•Ό ν•˜λŠ” λ‚΄μš©μ„ μ‹€μˆ˜λ‘œ frombunny 브랜치 κΈ°μ€€μœΌλ‘œ PR을 올리게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ£„μ†‘ν•©λ‹ˆλ‹€ 😭
이후 리뷰 반영 및 컀밋 νžˆμŠ€ν† λ¦¬ 정리λ₯Ό μœ„ν•΄, frombunny κΈ°μ€€μœΌλ‘œ μƒˆλ‘œμš΄ λΈŒλžœμΉ˜μ—μ„œ 컀밋을 μž¬κ΅¬μ„±ν•œ λ’€ step2 λΈŒλžœμΉ˜μ— λ°˜μ˜ν–ˆμŠ΅λ‹ˆλ‹€..!

Board board = new Board(BoardInitializer.init(InputView.readBoardSetting()));
GameController gameController = new GameController(board);
try (HikariDataSource hikariDataSource = createDataSource()) {
TransactionManager transactionManager = new TransactionManager(hikariDataSource);

BoardRepository boardRepository = new BoardRepository();

Board board = initBoard(transactionManager, boardRepository);

GameController gameController = new GameController(board, boardRepository, transactionManager);
gameController.run();

while (!board.isGameOver()) {
gameController.printBoard();
gameController.move();
OutputView.printBoard(board);
OutputView.printWinner(board.winner(), board.score(Camp.CHO), board.score(Camp.HAN));

transactionManager.executeTransaction(connection -> {
boardRepository.delete(connection, board);
return null;
}
);
}
}

private static HikariDataSource createDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl("jdbc:h2:~/janggi;INIT=RUNSCRIPT FROM 'src/main/resources/create_tables.sql'");
hikariConfig.setDriverClassName("org.h2.Driver");
hikariConfig.setUsername("sa");
hikariConfig.setPassword("");

return new HikariDataSource(hikariConfig);
}

private static Board initBoard(TransactionManager transactionManager, BoardRepository boardRepository) {
printSavedBoards(transactionManager, boardRepository);
int boardId = InputView.readBoardNumber();

Board board;
if (boardId == 0) {
board = Board.from(BoardInitializer.init(InputView.readBoardSetting()));
transactionManager.executeTransaction(connection -> {
boardRepository.save(connection, board);
return null;
});
return board;
}
return transactionManager.executeTransaction(connection -> boardRepository.findById(connection, (long) boardId));
}

gameController.printBoard();
gameController.printWinner();
private static void printSavedBoards(TransactionManager transactionManager, BoardRepository boardRepository) {
transactionManager.executeTransaction(connection -> {
List<BoardDto> boards = boardRepository.findAll(connection);
OutputView.printBoards(boards);
return null;
});
}
}
39 changes: 24 additions & 15 deletions src/main/java/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,48 @@

package controller;

import data.BoardRepository;
import data.TransactionManager;
import domain.board.Board;
import domain.board.Position;
import view.InputView;
import view.OutputView;

public class GameController {
private final Board board;
private final BoardRepository boardRepository;
private final TransactionManager transactionManager;

public GameController(Board board) {
public GameController(Board board, BoardRepository boardRepository, TransactionManager transactionManager) {
this.board = board;
this.boardRepository = boardRepository;
this.transactionManager = transactionManager;
}

public void move() {
while (true) {
public void run(){
while (board.isGameInProgress()) {
OutputView.printBoard(board);
try {
Position departure = parsePosition(InputView.readDeparturePosition());
Position destination = parsePosition(InputView.readDestinationPosition());
board.move(departure, destination);
return;
} catch (IllegalArgumentException exception) {
OutputView.printError(exception.getMessage());

transactionManager.executeTransaction(connection -> {
board.move(departure, destination);
boardRepository.save(connection, board);
return null;
});
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
} catch (RuntimeException e) {
if (e.getCause() instanceof IllegalArgumentException cause) {
System.out.println(cause.getMessage());
continue;
}
throw e;
}
}
}

public void printBoard() {
OutputView.printBoard(board);
}

public void printWinner() {
OutputView.printWinner(board.winner());
}

private Position parsePosition(String value) {
String[] tokens = value.split(",");
if (tokens.length != 2) {
Expand Down
111 changes: 111 additions & 0 deletions src/main/java/data/BoardDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package data;

import domain.piece.Camp;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class BoardDao {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

λ“€μ—¬μ“°κΈ°κ°€ 2단계λ₯Ό λ„˜μ–΄κ°€λŠ” 둜직이 λ§Žμ€ 것 κ°™λ„€μš”. λ©”μ„œλ“œ μΆ”μΆœλ‘œ 정리해보면 쒋을 것 κ°™μ•„μš”~

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

이 뢀뢄도 λ©”μ„œλ“œ μΆ”μΆœλ‘œ μ •λ¦¬ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€!

public Long insertBoard(Connection connection, boolean gameInProgress, String turn) {
String sql = "INSERT INTO boards (`game_in_progress`, `turn`) VALUES (?, ?)";
try (
PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
) {
preparedStatement.setBoolean(1, gameInProgress);
preparedStatement.setString(2, turn);

preparedStatement.executeUpdate();

return getGenerateId(preparedStatement);

} catch (SQLException e) {
throw new IllegalStateException("데이터 μ‚½μž…μ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.", e);
}
}

public Optional<BoardDto> getBoard(Connection connection, Long boardId) {
String sql = "SELECT `id`, `game_in_progress`, `turn` FROM boards WHERE `id` = (?)";
try (
PreparedStatement preparedStatement = connection.prepareStatement(sql)
) {
preparedStatement.setLong(1, boardId);

return getBoardDto(preparedStatement);
} catch (SQLException e) {
throw new IllegalStateException("데이터 μ‘°νšŒμ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.", e);
}

}

public List<BoardDto> getAllBoards(Connection connection) {
String sql = "SELECT `id`, `game_in_progress`, `turn` FROM boards WHERE `game_in_progress` = true ORDER BY `id`";
List<BoardDto> boards = new ArrayList<>();

try (PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
boards.add(mapRow(resultSet));
}
return boards;
} catch (SQLException e) {
throw new IllegalStateException("데이터 μ‘°νšŒμ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.", e);
}
}


public void deleteBoard(Connection connection, Long boardId) {
String sql = "DELETE FROM boards WHERE `id`=(?)";
try (
PreparedStatement preparedStatement = connection.prepareStatement(sql)
) {
preparedStatement.setLong(1, boardId);

preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new IllegalStateException("데이터 μ‚­μ œμ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.", e);
}
}

public void updateBoard(Connection connection, Long boardId, boolean gameInProgress, String turn) {
String sql = "UPDATE boards SET `game_in_progress` = (?), `turn` = (?) WHERE `id` = (?)";
try (
PreparedStatement preparedStatement = connection.prepareStatement(sql)
) {
preparedStatement.setBoolean(1, gameInProgress);
preparedStatement.setString(2, turn);
preparedStatement.setLong(3, boardId);

preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new IllegalStateException("데이터 μˆ˜μ •μ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.", e);
}
}

private Long getGenerateId(PreparedStatement preparedStatement) throws SQLException {
try (ResultSet resultSet = preparedStatement.getGeneratedKeys()) {
if (resultSet.next()) {
return resultSet.getLong(1);
}
throw new IllegalArgumentException("IDλ₯Ό μ‘°νšŒν•  수 μ—†μŠ΅λ‹ˆλ‹€.");
}
}

private Optional<BoardDto> getBoardDto(PreparedStatement preparedStatement) throws SQLException {
try (ResultSet resultSet = preparedStatement.executeQuery()) {
if (!resultSet.next()) {
return Optional.empty();
}
return Optional.of(mapRow(resultSet));
}
}

private BoardDto mapRow(ResultSet resultSet) throws SQLException {
return new BoardDto(
resultSet.getLong("id"),
resultSet.getBoolean("game_in_progress"),
Camp.valueOf(resultSet.getString("turn"))
);
}
}
10 changes: 10 additions & 0 deletions src/main/java/data/BoardDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package data;

import domain.piece.Camp;

public record BoardDto(
Long id,
boolean gameInProgress,
Camp turn
) {
}
69 changes: 69 additions & 0 deletions src/main/java/data/BoardRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package data;

import domain.board.Board;
import domain.board.Position;
import domain.piece.Camp;
import domain.piece.Piece;
import domain.piece.PieceType;

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

public class BoardRepository {
private final PieceDao pieceDao = new PieceDao();
private final BoardDao boardDao = new BoardDao();

public void save(Connection connection, Board board) {
Map<Position, Piece> pieces = board.pieces();

Long boardId;
if (board.id() == null) {
boardId = boardDao.insertBoard(connection, board.isGameInProgress(), board.turn().name());
board.assignId(boardId);
} else {
boardId = board.id();
boardDao.updateBoard(connection, boardId, board.isGameInProgress(), board.turn().name());
pieceDao.deleteAllByBoard(connection, boardId);
}

pieces.forEach((position, piece) ->
pieceDao.insertPiece(connection, boardId, piece.pieceType().name(),
piece.camp().name(), position.column(), position.row())
);
}

public Board findById(Connection connection, Long boardId) {
BoardDto boardDto = boardDao.getBoard(connection, boardId).orElseThrow(() ->
new IllegalArgumentException("μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μž₯κΈ°νŒμž…λ‹ˆλ‹€."));
List<PieceDto> piecesInfo = pieceDao.getAllPieceByBoard(connection, boardId);

Map<Position, Piece> pieces = new HashMap<>();
for (PieceDto piece : piecesInfo) {
Camp camp = piece.camp();
PieceType pieceType = piece.type();
pieces.put(new Position(piece.column(), piece.row()),
Piece.of(camp, pieceType));
}

Board board = new Board(pieces, boardDto.gameInProgress(), boardDto.turn());
board.assignId(boardDto.id());
return board;
}

public List<BoardDto> findAll(Connection connection) {
return boardDao.getAllBoards(connection);
}

public void delete(Connection connection, Board board) {
Long boardId = board.id();

if (boardId == null) {
throw new IllegalStateException("μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” κ²Œμž„μž…λ‹ˆλ‹€.");
}

pieceDao.deleteAllByBoard(connection, boardId);
boardDao.deleteBoard(connection, boardId);
}
}
Loading