-
Notifications
You must be signed in to change notification settings - Fork 166
[ 사이클1 - 미션 (보드 초기화 + 기물 이동)] 고래 미션 제출합니다. #269
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
base: miniminjae92
Are you sure you want to change the base?
Changes from all commits
8ed7716
d1fa894
a956456
c6fffa2
2306d36
98b7af5
8c0e6b9
5830535
07a7c91
151c12a
663a123
b4c9502
559f0f2
8dfc831
4b70abd
80c4f31
7b112e0
6937ac2
303e556
dd4f2ac
50f2eb9
21aa29e
da517e6
5cd420c
1ed9111
72210f2
7b99b94
3e6002d
d5f2ee7
5371e48
2cbe86c
ac6a56b
178cd12
2767292
92d1e8a
78870f0
193056f
c95e533
6567b11
e4c4558
a6a6570
3e24b68
37da877
50546c5
b4df2ef
96a44ff
fd6dfac
e2e879a
23862a7
f660c3f
c90daf6
2059839
d4dfde2
08c2567
47bb454
3b8a8f9
6d7b921
5f3e627
70eadf0
29c93f8
00889f3
cbffaf8
bbb9237
06db191
7120652
0fbc4d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import domain.GameManager; | ||
| import java.util.Scanner; | ||
| import view.InputView; | ||
| import view.OutputView; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| GameManager gameManager = new GameManager( | ||
| new InputView(new Scanner(System.in)), | ||
| new OutputView() | ||
| ); | ||
| gameManager.play(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class Destinations { | ||
| private final List<Position> positions; | ||
|
|
||
| public Destinations(List<Position> positions) { | ||
| validate(positions); | ||
| this.positions = List.copyOf(positions); | ||
| } | ||
|
|
||
| private void validate(List<Position> positions) { | ||
| if (positions.isEmpty()) { | ||
| throw new IllegalArgumentException("이동 가능한 목적지가 없습니다."); | ||
| } | ||
| } | ||
|
|
||
| public List<Position> getPositions() { | ||
| return positions; | ||
| } | ||
|
|
||
| public void validateDestinations(Position target) { | ||
| if (!positions.contains(target)) { | ||
| throw new IllegalArgumentException("이동할 수 없는 위치입니다."); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package domain; | ||
|
|
||
| import domain.board.Board; | ||
| import domain.piece.Piece; | ||
| import domain.player.Players; | ||
| import java.util.Map; | ||
|
|
||
| public class Game { | ||
| private Board board; | ||
| private final Players players; | ||
|
|
||
| public Game(Board board, Players players) { | ||
| this.board = board; | ||
| this.players = players; | ||
| } | ||
|
|
||
| public Side getCurrentSide() { | ||
| return players.getCurrentSide(); | ||
| } | ||
|
|
||
| public Destinations selectSource(Position position) { | ||
| Piece piece = board.getPiece(position); | ||
| players.getCurrentPlayer().validateAlly(piece); | ||
| return findDestinations(position); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| public void move(Position source, Position target) { | ||
| Destinations destinations = selectSource(source); | ||
| destinations.validateDestinations(target); | ||
| movePiece(source, target); | ||
| players.switchPlayer(); | ||
| } | ||
|
|
||
| private Destinations findDestinations(Position position) { | ||
| return board.findDestinations(position); | ||
| } | ||
|
|
||
| private void movePiece(Position source, Position target) { | ||
| this.board = board.movePiece(source, target); | ||
| } | ||
|
|
||
| public Map<Position, Piece> getBoard() { | ||
| return board.getBoard(); | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| public boolean isOver() { | ||
| return board.isGameOver(); | ||
| } | ||
|
|
||
| public String getWinner() { | ||
| return players.getWaitingPlayerName(); | ||
| } | ||
|
Comment on lines
+50
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
다른 네이밍은 없을까요? |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| package domain; | ||
|
|
||
| import domain.board.Board; | ||
| import domain.board.BoardFactory; | ||
| import domain.board.Formation; | ||
| import domain.board.FormationCommand; | ||
| import domain.player.Name; | ||
| import domain.player.Players; | ||
| import java.util.List; | ||
| import java.util.function.Supplier; | ||
| import view.InputParser; | ||
| import view.InputView; | ||
| import view.OutputView; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| public class GameManager { | ||
| private final InputView inputView; | ||
| private final OutputView outputView; | ||
|
|
||
| public GameManager(InputView inputView, OutputView outputView) { | ||
| this.inputView = inputView; | ||
| this.outputView = outputView; | ||
| } | ||
|
|
||
| public void play() { | ||
| Game game = initializeGame(); | ||
| outputView.printBoard(game.getBoard()); | ||
| while (!game.isOver()) { | ||
| playTurn(game); | ||
| } | ||
| outputView.printWinner(game.getWinner()); | ||
| } | ||
|
|
||
| private Game initializeGame() { | ||
| Name choName = getPlayerName(Side.CHO); | ||
| Players players = retry(() -> { | ||
| Name hanName = getPlayerName(Side.HAN); | ||
| return Players.createInitial(choName, hanName); | ||
| }); | ||
| Board board = BoardFactory.create(getFormation(Side.CHO), getFormation(Side.HAN)); | ||
| return new Game(board, players); | ||
| } | ||
|
|
||
| private Name getPlayerName(Side side) { | ||
| return retry(() -> InputParser.parseName(inputView.readPlayerName(side))); | ||
| } | ||
|
|
||
| private Formation getFormation(Side side) { | ||
| return retry(() -> Formation.from(FormationCommand.from(inputView.readFormation(side)))); | ||
| } | ||
|
|
||
| private void playTurn(Game game) { | ||
| Position source = selectPiecePosition(game); | ||
| retry(() -> { | ||
| Position target = InputParser.parsePosition(inputView.readTargetPosition()); | ||
| game.move(source, target); | ||
| }); | ||
| outputView.printBoard(game.getBoard()); | ||
| } | ||
|
|
||
| private Position selectPiecePosition(Game game) { | ||
| return retry(() -> { | ||
| Position position = InputParser.parsePosition(inputView.readSourcePosition(game.getCurrentSide())); | ||
| List<Position> destinations = game.selectSource(position).getPositions(); | ||
| outputView.printDestinations(destinations); | ||
| return position; | ||
| }); | ||
| } | ||
|
|
||
| private <T> T retry(Supplier<T> supplier) { | ||
| while (true) { | ||
| try { | ||
| return supplier.get(); | ||
| } catch (IllegalArgumentException e) { | ||
| outputView.printError(e.getMessage()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void retry(Runnable action) { | ||
| while (true) { | ||
| try { | ||
| action.run(); | ||
| return; | ||
| } catch (IllegalArgumentException e) { | ||
| outputView.printError(e.getMessage()); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| package domain; | ||
|
|
||
| import domain.strategy.Direction; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
|
|
||
| public class Position { | ||
| private static final Map<Integer, Position> CACHE = new HashMap<>(); | ||
|
|
||
| public static final int MIN = 0; | ||
| public static final int MAX_X = 8; | ||
| public static final int MAX_Y = 9; | ||
|
|
||
| private final int x; | ||
| private final int y; | ||
|
|
||
| static { | ||
| for (int x = MIN; x <= MAX_X; x++) { | ||
| for (int y = MIN; y <= MAX_Y; y++) { | ||
| CACHE.put(generateKey(x, y), new Position(x, y)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private Position(int x, int y) { | ||
| this.x = x; | ||
| this.y = y; | ||
| } | ||
|
|
||
| public static Position of(int x, int y) { | ||
| validateRange(x, y); | ||
| return CACHE.get(generateKey(x, y)); | ||
| } | ||
|
|
||
| private static void validateRange(int x, int y) { | ||
| if (!isWithinRange(x, y)) { | ||
| throw new IllegalArgumentException(String.format("범위를 벗어난 좌표입니다: (%d, %d)", x, y)); | ||
| } | ||
| } | ||
|
|
||
| public boolean canMove(Direction direction) { | ||
| return isWithinRange(this.x + direction.getDx(), this.y + direction.getDy()); | ||
| } | ||
|
|
||
| public boolean canMove(List<Direction> sequence) { | ||
| if (sequence.isEmpty()) { | ||
| return true; | ||
| } | ||
|
|
||
| Direction direction = sequence.getFirst(); | ||
| if (!canMove(direction)) { | ||
| return false; | ||
| } | ||
|
|
||
| return move(direction).canMove(sequence.subList(1, sequence.size())); | ||
| } | ||
|
|
||
| public Position move(Direction direction) { | ||
| return Position.of(this.x + direction.getDx(), this.y + direction.getDy()); | ||
| } | ||
|
|
||
| public static boolean isWithinRange(int x, int y) { | ||
| return x >= MIN && x <= MAX_X && y >= MIN && y <= MAX_Y; | ||
| } | ||
|
|
||
| private static int generateKey(int x, int y) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Position이 캐싱을 통해 동일 좌표에 대해 같은 인스턴스를 반환하고 있는데, |
||
| return x * 31 + y; | ||
| } | ||
|
|
||
| public int getX() { return x; } | ||
| public int getY() { return y; } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (!(o instanceof Position position)) return false; | ||
| return x == position.x && y == position.y; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(x, y); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return String.format("(%d, %d)", x, y); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public enum Side { | ||
| CHO("초") { | ||
| @Override | ||
| public int baseY() { | ||
| return 0; | ||
| } | ||
|
|
||
| @Override | ||
| public int generalY() { | ||
| return 1; | ||
| } | ||
|
|
||
| @Override | ||
| public int cannonY() { | ||
| return 2; | ||
| } | ||
|
|
||
| @Override | ||
| public int soldierY() { | ||
| return 3; | ||
| } | ||
|
|
||
| @Override | ||
| public List<Integer> formationX() { | ||
| return List.of(1, 2, 6, 7); | ||
| } | ||
| }, | ||
| HAN("한") { | ||
| @Override | ||
| public int baseY() { | ||
| return 9; | ||
| } | ||
|
|
||
| @Override | ||
| public int generalY() { | ||
| return 8; | ||
| } | ||
|
|
||
| @Override | ||
| public int cannonY() { | ||
| return 7; | ||
| } | ||
|
|
||
| @Override | ||
| public int soldierY() { | ||
| return 6; | ||
| } | ||
|
|
||
| @Override | ||
| public List<Integer> formationX() { | ||
| return List.of(7, 6, 2, 1); | ||
| } | ||
| }; | ||
|
|
||
| private final String name; | ||
|
|
||
| Side(String name) { | ||
| this.name = name; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
SRP를 위반한 것 아닌가요? |
||
|
|
||
| public abstract int baseY(); | ||
| public abstract int generalY(); | ||
| public abstract int cannonY(); | ||
| public abstract int soldierY(); | ||
| public abstract List<Integer> formationX(); | ||
|
|
||
| public boolean isAlly(Side other) { | ||
| return this.equals(other); | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 메서드는 절차적으로 호출하지 않으면 의도한대로 사용되지 않을 우려가 있어보이는데요.
구조적으로 안전하게 설계를 개선해보면 좋을것 같네요.