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

[1단계 - 장기] 헤일러(민서현) 미션 제출합니다. #10

Merged
merged 85 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
c05b6eb
docs: 프로그램 실행 흐름 기능 작성
ljhee92 Mar 18, 2025
bc91c23
feat(Point): 좌표 클래스 추가
threepebbles Mar 18, 2025
88f09bf
feat(Direction): 방향을 의미하는 상수 추가
threepebbles Mar 18, 2025
fedaaa3
feat(Node, Edge): 노드, 엣지 클래스 추가
threepebbles Mar 18, 2025
63c152f
feat(BoardInitializer): 노드와 엣지 정보 초기화
threepebbles Mar 18, 2025
5448de9
feat(SangMaOrderCommand): 상마 순서를 의미하는 enum 추가
ljhee92 Mar 19, 2025
b7eaff1
feat: 팀을 구분하기 위한 enum 추가
ljhee92 Mar 19, 2025
627e724
feat(Piece): 기물 역할 클래스 추가
ljhee92 Mar 19, 2025
cd7657f
feat(BoardInitializer): 초나라 기물 배치 초기화 기능 추가
ljhee92 Mar 19, 2025
1978af8
feat(BoardInitializer): 상마 순서에 따른 기물 배치 초기화 기능 추가
ljhee92 Mar 19, 2025
2ab255f
refactor: BoardInitializer 리팩터링
threepebbles Mar 19, 2025
5ea034d
refactor: 패키지 이동
threepebbles Mar 19, 2025
921154d
feat: 특정 좌표에 기물 존재 여부 확인 기능 추가
threepebbles Mar 19, 2025
2d39066
feat(Piece): 각 기물의 종류를 구분하는 기능 추가
threepebbles Mar 19, 2025
216581f
feat(OutputView): 장기판 출력 기능 추가
threepebbles Mar 19, 2025
51e5c82
feat(OutputView): 팀 색깔 구분 기능 추가
ljhee92 Mar 19, 2025
d3021ac
refactor: 기물이 가진 팀을 묻도록 리팩터링
ljhee92 Mar 19, 2025
c72d5d9
feat(Wang): 왕의 이동 가능 여부 확인 기능 추가
threepebbles Mar 19, 2025
c1b5611
feat(Sa): 사의 이동 가능 여부 확인 기능 추가
ljhee92 Mar 19, 2025
af7b771
fix: 노드 엣지 초기화 기능 수정
ljhee92 Mar 19, 2025
edbd206
feat(Byeong): 병의 이동 가능 여부 확인 기능 추가
ljhee92 Mar 19, 2025
6ce8aff
feat(Cha): 차의 이동 가능 여부 확인 기능 추가
threepebbles Mar 19, 2025
225fe9d
feat(Ma): 마의 이동 가능 여부 확인 기능 추가
threepebbles Mar 19, 2025
c39fbe5
feat(Sang): 상의 이동 가능 여부 확인 기능 추가
ljhee92 Mar 19, 2025
5473e7c
refactor: 변수명 개선, 인덴트 깊이 개선
threepebbles Mar 19, 2025
13db4fa
refactor: 가독성 개선
threepebbles Mar 19, 2025
d88377a
fix: 테스트 코드 컴파일 에러 수정
threepebbles Mar 19, 2025
fea65fd
feat(Po): 포의 이동 가능 여부 확인 기능 추가
threepebbles Mar 19, 2025
11b48a6
feat: 상마 순서 입력 기능 추가
ljhee92 Mar 19, 2025
1f87130
feat: 이동할 기물의 위치 입력 기능 추가
ljhee92 Mar 19, 2025
344458c
refactor(Board): 중복 메서드 제거, 네이밍 개선
ljhee92 Mar 20, 2025
7c3a111
feat(OutputView): 승패 결과 출력 기능 추가
ljhee92 Mar 20, 2025
2cb102e
feat(JanggiManager): 말을 움직이는 기능 추가
ljhee92 Mar 20, 2025
66bec8f
feat: 순서대로 장기 게임을 진행하는 기능 추가
ljhee92 Mar 20, 2025
bbd2d83
feat(ErrorHandler): 메서드 실행 중 예외 발생 시 재실행하는 기능 추가
threepebbles Mar 20, 2025
71a929f
refactor(Board): 특정 위치의 놓인 기물의 종류를 확인하는 기능 추가
threepebbles Mar 20, 2025
960a831
test: Board 테스트 추가
threepebbles Mar 20, 2025
cd3247a
fix: 특정 위치의 기물의 종류를 파악하는 기능 수정
threepebbles Mar 20, 2025
8d85ddb
fix: 턴에 맞는 기물을 움직일 수 있게 수정
threepebbles Mar 20, 2025
6af5c8a
refactor: 용어 수정(노드 -> 위치)
threepebbles Mar 20, 2025
03af29c
test: Node 테스트 추가
threepebbles Mar 20, 2025
fc12f9a
refactor: 네이밍 개선, 메서드 분리
threepebbles Mar 20, 2025
e044c10
refactor: 패키지 이동
threepebbles Mar 20, 2025
e8bc351
refactor: 네이밍 개선, 네이밍 컨벤션에 맞게 수정
threepebbles Mar 20, 2025
4b7db0c
refactor(Turn): 내부 static 클래스로 전환
threepebbles Mar 20, 2025
9744b5e
refactor: 네이밍 개선
threepebbles Mar 20, 2025
60df63d
refactor(Node): edges() 제거
threepebbles Mar 20, 2025
08d5848
refactor: 메서드 내 변수 상수화
threepebbles Mar 20, 2025
05e5f28
refactor: 변수명 변경
threepebbles Mar 20, 2025
aa16beb
refactor: 상수 final 처리, ERROR prefix 추가
ljhee92 Mar 20, 2025
c268bd1
Merge branch 'step1' of https://github.com/ljhee92/java-janggi into s…
threepebbles Mar 20, 2025
6270d81
remove: .gitkeep 삭제
threepebbles Mar 20, 2025
2af89bd
refactor(FixedMovePattern): 마와 상 움직임 패턴을 enum 클래스로 분리
threepebbles Mar 22, 2025
20412e7
refactor(Board): Map<Node, Piece> 타입을 Map<Point, Piece> 타입으로 변경 및 적용
threepebbles Mar 22, 2025
6472401
refactor: 상수 위치 이동
threepebbles Mar 22, 2025
e9282f9
refactor: 상수명 개선
threepebbles Mar 22, 2025
492ddf1
refactor(Board): Board가 스스로 게임의 종료 여부를 알도록 수정
threepebbles Mar 22, 2025
89ebb95
refactor: 클래스명 개선
threepebbles Mar 22, 2025
47a2b80
fix(Board): 게임 종료 조건 수정
threepebbles Mar 22, 2025
38ad5bc
refactor: 네이밍 개선
threepebbles Mar 23, 2025
9fec375
refactor(Piece): canMove에서 파라미터 타입을 Node가 아닌 Point를 받아서 기능을 수행하도록 수정
threepebbles Mar 23, 2025
0d1c4dc
refactor: 클래스명 개선
threepebbles Mar 23, 2025
7c66006
test: board가 아니라 각 piece 객체가 canMove()를 수행하도록 수정
threepebbles Mar 23, 2025
7edb1a6
refactor(Path): Path 클래스 enum 상수화
threepebbles Mar 23, 2025
a0dd32c
refactor(Piece): 파라미터로 팀을 확인하는 기능 hasTeam() 제거, 팀 enum을 반환하는 기능 team(…
threepebbles Mar 23, 2025
6d9ddd9
test(NodeTest): 노드 테스트 추가
threepebbles Mar 23, 2025
6c59923
refactor: exist -> exists 용어 통일
threepebbles Mar 23, 2025
10a4769
refactor: 패키지 이동
threepebbles Mar 23, 2025
5ed393d
refactor(Direction): 상하좌우 방향 리스트(VERTICALS) 상수화
threepebbles Mar 23, 2025
db21822
fix: 상수에 final 키워드 추가
threepebbles Mar 23, 2025
679785f
refactor: 상마 순서 예외 메시지 개선
threepebbles Mar 23, 2025
0ff42ef
refactor: 게임 종료 시 승리한 팀을 찾는 기능 옮김(JanggiManager -> Board)
threepebbles Mar 23, 2025
ad6a041
feat(PointNodeMapperFactory): PointNodeMapper의 생성 책임을 클래스로 분리
threepebbles Mar 23, 2025
f04434e
refactor: 메서드 파라미터에 final 키워드 추가
threepebbles Mar 23, 2025
6060d63
refactor: 입출력 메시지 개선
threepebbles Mar 23, 2025
1d0f997
refactor(Node): 불필요한 필드(Point) 제거
threepebbles Mar 23, 2025
ccb2f61
test(NodeTest): 출발 노드로부터 간선이 있는 방향은 true, 없는 방향은 false를 반환하는 기능 테스트 추가
threepebbles Mar 23, 2025
4668962
refactor: 동일한 로직 메서드 분리(DRY 원칙)
threepebbles Mar 23, 2025
5e26b6c
refactor: 파라미터에 final 키워드 추가
threepebbles Mar 23, 2025
1bffd19
refactor: 메서드명 개선
threepebbles Mar 24, 2025
6999e71
refactor: 변수 네이밍 일관되게 수정(board -> pieceByPoint)
threepebbles Mar 24, 2025
0b7bc22
refactor: 가독성을 위해 메서드 분리
threepebbles Mar 24, 2025
3f6ea82
refactor: 가독성 개선을 위해 에러 메시지에 줄바꿈 추가
threepebbles Mar 24, 2025
f3838b9
fix: 기물을 움직일 수 없는 경우에 턴이 바뀌지 않도록 수정
threepebbles Mar 24, 2025
f92a46e
refactor: 보드판 출력 시기 수정
threepebbles Mar 24, 2025
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
91 changes: 90 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,92 @@
# java-janggi

장기 미션 저장소
## 프로그램 실행 흐름
Copy link

Choose a reason for hiding this comment

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

아무래도 첫 리뷰 요청 마감 기간이 있다보니 시간이 조금 빠듯하셔서 프롤로그까지 작성하시기가 어려우셨을 것 같아요.
다음 리뷰 요청 전에는 프롤로그 작성도 같이 부탁드릴게요. 🙏😉


### 게임 시작

- 게임 시작 안내 메시지를 출력한다.

```
장기 게임에 오신 것을 환영합니다.
```

### 상마 순서 입력

- 상마 순서 결정을 위한 입력을 받는다.

```
한나라 상마 순서를 입력해주세요. (예: 3)
1. 상마상마
2. 상마마상
3. 마상상마
4. 마상마상
1

초나라 상마 순서를 입력해주세요. (예: 3)
1. 상마상마
2. 상마마상
3. 마상상마
4. 마상마상
2
```

- 예외
- 올바르지 않은 입력이 들어온 경우 에러 메시지를 출력한다.

```
초나라 상마 순서를 입력해주세요. (예: 3)
1. 상마상마
2. 상마마상
3. 마상상마
4. 마상마상
6
[ERROR] 올바른 상마 순서 번호를 입력해주세요. (예: 3)
```

### 기물 위치 초기화

- 입력한 상마 순서에 따라 기물 위치를 초기화한다.

### 이동 커맨드 입력

- move src dst 양식으로 입력해야 한다.
- src에 있는 내 기물을 dst로 이동한다.

```
현재 턴 : 초나라
이동할 기물의 현재 위치와 이동할 위치를 입력해주세요. (예: move 1,1 2,1)
move 1,1 2,1
```

- 예외
- src가 빈 칸인 경우 예외가 발생한다.
- src에 상대 기물이 있는 경우 예외가 발생한다.
- src에서 dst로 이동할 수 없는 경우 예외가 발생한다.

### 보드 출력

- 현재 장기판 상태를 출력한다.
- 팀은 색깔로 구분한다.
- 초나라 : 초록색
- 한나라 : 빨간색

```
차 상 마 사 ㅁ 사 상 마 차
ㅁ ㅁ ㅁ ㅁ 왕 ㅁ ㅁ ㅁ ㅁ
ㅁ 포 ㅁ ㅁ ㅁ ㅁ ㅁ 포 ㅁ
병 ㅁ 병 ㅁ 병 ㅁ 병 ㅁ 병
ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ
ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ
병 ㅁ 병 ㅁ 병 ㅁ 병 ㅁ 병
ㅁ 포 ㅁ ㅁ ㅁ ㅁ ㅁ 포 ㅁ
ㅁ ㅁ ㅁ ㅁ 왕 ㅁ ㅁ ㅁ ㅁ
차 상 마 사 ㅁ 사 마 상 차
```

### 승패 결과 출력

- 이동 중간에 왕이 죽으면 승패 결과를 출력한다.

```
초나라의 승리입니다.
```
Empty file removed src/main/java/.gitkeep
Empty file.
9 changes: 9 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import manager.JanggiGameManager;

public class Application {

public static void main(String[] args) {
JanggiGameManager janggiGameManager = new JanggiGameManager();
janggiGameManager.startGame();
}
}
153 changes: 153 additions & 0 deletions src/main/java/domain/board/Board.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package domain.board;

import domain.piece.Piece;
import domain.piece.PieceType;
import domain.piece.Team;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class Board {

private final Map<Point, Piece> pieceByPoint;
private final PointNodeMapper pointNodeMapper;

public Board(final Map<Point, Piece> pieceByPoint, final PointNodeMapper pointNodeMapper) {
this.pieceByPoint = pieceByPoint;
this.pointNodeMapper = pointNodeMapper;
}

public boolean isEnd() {
return !isTwoWangsAlive();
}

private boolean isTwoWangsAlive() {
Copy link

Choose a reason for hiding this comment

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

잘 생각해보면 isEnd의 반대니까 isPlaying() 같은 네이밍을 지어도 되지 않을까요?
두개의 왕이 살아있다는 네이밍 보다는 진행중이다가 조금 더 의도를 직관적으로 이해할 수 있지 않을까 싶어요. 😃

return findTeamsOfWang().containsAll(List.of(Team.CHO, Team.HAN));
Copy link

Choose a reason for hiding this comment

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

추가적으로 워딩을 생각했을 때, 아래와 같은 로직이 네이밍이랑 조금 더 매칭이 잘되지 않을까요? 🤔

Suggested change
return findTeamsOfWang().containsAll(List.of(Team.CHO, Team.HAN));
findTeamsOfWang().size() == 2;

Copy link
Author

Choose a reason for hiding this comment

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

장기의 원래 룰대로라면 각 팀의 왕은 1개씩만 존재해야 하지만, 아래와 같은 예외 상황이 발생할 수 있다고 생각해서 팀의 종류까지 확인하게 했어요!

  • 한 팀의 왕이 2개 이상이 존재할 수 있는 경우

}

public Team findWinTeam() {
if (!isEnd()) {
throw new IllegalStateException("아직 게임이 끝나지 않았습니다.");
}
Set<Team> foundTeam = findTeamsOfWang();
if (foundTeam.contains(Team.CHO)) {
return Team.CHO;
}
return Team.HAN;
Comment on lines +34 to +37
Copy link

Choose a reason for hiding this comment

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

Team 객체에게 반대 의 Team을 알려달라고 메시지를 보내볼 수 있지 않을까요? 😃

Copy link
Author

Choose a reason for hiding this comment

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

혹시 힌트 좀 주실 수 있을까요? 🥺

}

private Set<Team> findTeamsOfWang() {
return pieceByPoint.values().stream()
.filter(piece -> piece.type() == PieceType.WANG)
Copy link

Choose a reason for hiding this comment

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

piece 객체에게 왕인지 여부를 메시지를 보내서 물어보면 어떨까요? 😃

Copy link
Author

Choose a reason for hiding this comment

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

현재 piece 객체에게 메시지를 보내서 물어보는 방법은 아래의 3가지가 떠오릅니다.
1번 방법: boolean isWang(), boolean isPo()를 추가한다.

piece.isWang(); 

2번 방법: boolean hasType(PieceType pieceType)을 추가한다.

piece.hasType(PieceType.WANG);

3번 방법: 현행 유지

step2.1에서 기물의 종류에 따라 점수를 부여해야 하기 때문에, 모든 기물들의 구체 클래스 타입을 확인해야 하므로 enum PieceType을 사용하지 않기는 어려울 것 같습니다. PieceType type() 기능이 있는데 이를 이용하지 않고 인터페이스에 boolean isWang()을 추가해서 사용하는 것은 인터페이스에 중복된 기능이 추가되는 느낌을 받았습니다. 로키는 어떻게 생각하시나요?

Copy link
Author

Choose a reason for hiding this comment

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

다시 생각해보니 추상 메서드로 int score()를 둔다면 PieceType을 사용하지 않아도 각 기물의 점수를 다형성을 이용해서 계산할 수 있겠네요..! 좀 더 고민해보겠습니다.

.map(Piece::team)
.collect(Collectors.toSet());
}

public boolean canMove(final Point source, final Point destination) {
if (!existsPiece(source)) {
return false;
}
Piece piece = getPieceByPoint(source);
return piece.canMove(source, destination, this);
}

public void movePiece(final Point source, final Point destination) {
Copy link

Choose a reason for hiding this comment

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

image

이동할 수 있는 경로인 것 같은데 적의 말이 있으니 이동하지 못하는 것 같아요. 👀
적군의 말을 잡아먹지는 못하는 것 같은데, 이 부분 확인해주실 수 있을까요? 😃

Copy link
Author

Choose a reason for hiding this comment

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

테스트 해보았는데 move와 6,2 사이에 공백이 2개 입력되어서 해당 예외가 발생한 것 같아요!
커맨드와 좌표 사이에 여러 공백이 들어와도 하나로 처리할 수 있는 방법을 생각해보겠습니다. 🤔

Piece sourcePiece = getPieceByPoint(source);
if (!sourcePiece.canMove(source, destination, this)) {
throw new IllegalArgumentException(source + " -> " + destination + " [ERROR] 이동할 수 없는 경로입니다.");
}

pieceByPoint.put(destination, sourcePiece);
removePiece(source);
}

public boolean existsPiece(final Point point) {
if (!existsPoint(point)) {
return false;
}
return pieceByPoint.containsKey(point);
Comment on lines +66 to +69
Copy link

Choose a reason for hiding this comment

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

아래와 같이 변경해볼 수 있을 것 같아요. 😃

Suggested change
if (!existsPoint(point)) {
return false;
}
return pieceByPoint.containsKey(point);
return existsPoint(point) && pieceByPoint.containsKey(point);

}

private boolean existsPoint(final Point point) {
return pointNodeMapper.existsPoint(point);
}

public boolean existsPo(final Point point) {
if (!existsPiece(point)) {
return false;
}
Piece piece = getPieceByPoint(point);
return piece.type() == PieceType.PO;
Copy link

Choose a reason for hiding this comment

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

piece 객체에게 PO와 타입이 같은지 메시지를 보내볼 수 있을 것 같아요.

}

public void removePiece(final Point point) {
if (!existsPiece(point)) {
return;
}
Piece piece = getPieceByPoint(point);
pieceByPoint.remove(point, piece);
}

public boolean matchTeam(final Point point, final Team team) {
if (!existsPiece(point)) {
return false;
}
Piece piece = getPieceByPoint(point);
return piece.team() == team;
}

public boolean hasPieceType(final Point point, final PieceType pieceType) {
if (!existsPiece(point)) {
return false;
}
Piece piece = getPieceByPoint(point);
return piece.type() == pieceType;
}

private Piece getPieceByPoint(final Point point) {
if (!existsPiece(point)) {
throw new IllegalArgumentException(point + ": [ERROR] 해당 좌표에 기물이 존재하지 않습니다.");
}
return pieceByPoint.get(point);
}

public boolean existsNextPoint(final Point point, final Direction direction) {
if (!existsPoint(point)) {
return false;
}
Node node = pointNodeMapper.getNodeByPoint(point);
return node.hasNextNode(direction);
}

public Point getNextPoint(final Point point, final Direction direction) {
Copy link

Choose a reason for hiding this comment

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

(질문) 전체적으로 방어적 검증(?)이 과하지는 않은지 피드백 받고 싶습니다.

저는 성능적으로 큰 문제만 없다면 부족한 것 보다는 차라리 방어 로직이 과한게 낫다고 생각해요. 👀

또한 getNextPoint와 existsNextPoint는 공개 메서드이기 때문에 언제 어디서 사용되게 될지 모른다고 생각해요. 🤔
그 때는 지금과는 달리 existsNextPoint 이후에 getNextPoint가 호출된다는 보장이 없을 것 같아요.
이런 관점에서는 각각의 메서드에 모두 유효성 검증을 수행해주는게 더 좋다고 생각되지 않으시나요? 😃

Copy link

Choose a reason for hiding this comment

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

이런 부분이 싫으시다면 getNextPoint를 실패했을 때, 예외를 던지지 않고 Optional로 감싼 결과를 반환하여, 필요한 위치에서 적절히 필터링 혹은 예외처리를 하라고 명시적을 의도를 드러내줄 수도 있을 것 같아요. 🤔

validateExistPoint(point);
Node node = pointNodeMapper.getNodeByPoint(point);
Node nextNode = node.getNextNodeByDirection(direction);
return pointNodeMapper.getPointByNode(nextNode);
}

public boolean canMoveByPath(final Point point, final Path path) {
if (!existsPoint(point)) {
return false;
}
Node node = pointNodeMapper.getNodeByPoint(point);
return node.canMoveByPath(path);
}

public Point getPointMovedByPath(final Point point, final Path path) {
validateExistPoint(point);
Node node = pointNodeMapper.getNodeByPoint(point);
return pointNodeMapper.getPointByNode(node.moveByPath(path));
}

private void validateExistPoint(final Point point) {
if (!existsPoint(point)) {
throw new IllegalArgumentException(point.row() + ", " + point.column() + ": 존재하지 않는 좌표입니다.");
}
}

public Map<Point, Piece> getPieceByPoint() {
return pieceByPoint;
}
}
109 changes: 109 additions & 0 deletions src/main/java/domain/board/BoardGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package domain.board;

import domain.piece.Byeong;
import domain.piece.Cha;
import domain.piece.Ma;
import domain.piece.Piece;
import domain.piece.PieceType;
import domain.piece.Po;
import domain.piece.Sa;
import domain.piece.Sang;
import domain.piece.Team;
import domain.piece.Wang;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import view.SangMaOrderCommand;

public class BoardGenerator {

public Board generateBoard(final SangMaOrderCommand hanSangMaOrderCommand,
final SangMaOrderCommand choSangMaOrderCommand) {
PointNodeMapperFactory pointNodeMapperFactory = new PointNodeMapperFactory();
PointNodeMapper pointNodeMapper = pointNodeMapperFactory.createDefaultPointNodeMapper();
Map<Point, Piece> pieceByPoint = createPieces(hanSangMaOrderCommand, choSangMaOrderCommand);

return new Board(pieceByPoint, pointNodeMapper);
}

private Map<Point, Piece> createPieces(
final SangMaOrderCommand hanSangMaOrderCommand,
final SangMaOrderCommand choSangMaOrderCommand) {
Map<Point, Piece> pieceByPoint = new HashMap<>();
List<Point> hanSangMaPoints = List.of(Point.of(1, 2), Point.of(1, 3), Point.of(1, 7), Point.of(1, 8));
initializeHanPieces(hanSangMaPoints, hanSangMaOrderCommand, pieceByPoint);

List<Point> choSangMaPoints = List.of(Point.of(10, 2), Point.of(10, 3), Point.of(10, 7), Point.of(10, 8));
initializeChoPieces(choSangMaPoints, choSangMaOrderCommand, pieceByPoint);

return pieceByPoint;
}

private void initializeHanPieces(final List<Point> sangMaPoints,
final SangMaOrderCommand sangMaOrderCommand,
final Map<Point, Piece> pieceByPoint) {
pieceByPoint.put(Point.of(4, 1), new Byeong(Team.HAN));
pieceByPoint.put(Point.of(4, 3), new Byeong(Team.HAN));
pieceByPoint.put(Point.of(4, 5), new Byeong(Team.HAN));
pieceByPoint.put(Point.of(4, 7), new Byeong(Team.HAN));
pieceByPoint.put(Point.of(4, 9), new Byeong(Team.HAN));

pieceByPoint.put(Point.of(3, 2), new Po(Team.HAN));
pieceByPoint.put(Point.of(3, 8), new Po(Team.HAN));

pieceByPoint.put(Point.of(2, 5), new Wang(Team.HAN));

pieceByPoint.put(Point.of(1, 1), new Cha(Team.HAN));
pieceByPoint.put(Point.of(1, 4), new Sa(Team.HAN));
pieceByPoint.put(Point.of(1, 6), new Sa(Team.HAN));
pieceByPoint.put(Point.of(1, 9), new Cha(Team.HAN));
Deque<Piece> sangMaOrder = createSangMaByCommand(sangMaOrderCommand, Team.HAN);
for (Point point : sangMaPoints) {
pieceByPoint.put(point, sangMaOrder.removeFirst());
}
}

private void initializeChoPieces(final List<Point> sangMaPoints,
final SangMaOrderCommand sangMaOrderCommand,
final Map<Point, Piece> pieceByPoint) {
pieceByPoint.put(Point.of(7, 1), new Byeong(Team.CHO));
pieceByPoint.put(Point.of(7, 3), new Byeong(Team.CHO));
pieceByPoint.put(Point.of(7, 5), new Byeong(Team.CHO));
pieceByPoint.put(Point.of(7, 7), new Byeong(Team.CHO));
pieceByPoint.put(Point.of(7, 9), new Byeong(Team.CHO));

pieceByPoint.put(Point.of(8, 2), new Po(Team.CHO));
pieceByPoint.put(Point.of(8, 8), new Po(Team.CHO));

pieceByPoint.put(Point.of(9, 5), new Wang(Team.CHO));

pieceByPoint.put(Point.of(10, 1), new Cha(Team.CHO));
pieceByPoint.put(Point.of(10, 4), new Sa(Team.CHO));
pieceByPoint.put(Point.of(10, 6), new Sa(Team.CHO));
pieceByPoint.put(Point.of(10, 9), new Cha(Team.CHO));
Deque<Piece> sangMaOrder = createSangMaByCommand(sangMaOrderCommand, Team.CHO);
for (Point point : sangMaPoints) {
pieceByPoint.put(point, sangMaOrder.removeFirst());
}
}

private Deque<Piece> createSangMaByCommand(final SangMaOrderCommand sangMaOrderCommand,
final Team team) {
List<PieceType> pieceTypes = sangMaOrderCommand.getPieceTypes();
Deque<Piece> pieces = new ArrayDeque<>();
for (PieceType pieceType : pieceTypes) {
pieces.addLast(createPiece(pieceType, team));
}
return pieces;
}

private Piece createPiece(final PieceType pieceType, final Team team) {
return switch (pieceType) {
case SANG -> new Sang(team);
case MA -> new Ma(team);
default -> throw new IllegalArgumentException("[ERROR] 상 또는 마가 아닙니다.");
};
}
}
Loading