diff --git a/src/main/java/cleancode/minesweeper/tobe/Cell.java b/src/main/java/cleancode/minesweeper/tobe/Cell.java new file mode 100644 index 000000000..f862631e6 --- /dev/null +++ b/src/main/java/cleancode/minesweeper/tobe/Cell.java @@ -0,0 +1,50 @@ +package cleancode.minesweeper.tobe; + +public class Cell { + public static final String CLOSED_CELL_MARK = "□"; + public static final String OPENED_CELL_MARK = "■"; + public static final String LAND_MINE_MARK = "☼"; + public static final String FLAG_MARK = "⚑"; + private boolean isLandMine = false; + private boolean isFlag = false; + private boolean isOpen = false; + private Integer landMineCount = 0; + public void open() { + isOpen = true; + } + public void flag() { + if (isOpen) return; + isFlag = true; + } + + public boolean isLandMine() { + return isLandMine; + } + + public void applyLandMineCount(int count) { + landMineCount = count; + } + + public boolean isChecked() { + return isOpen || isFlag; + } + + @Override + public String toString() { + if (isOpen) { + if (isLandMine) return LAND_MINE_MARK; + if (landMineCount == 0) return OPENED_CELL_MARK; + return landMineCount.toString(); + } + if (isFlag) return FLAG_MARK; + return CLOSED_CELL_MARK; + } + + private Cell(boolean isLandMine) { + this.isLandMine = isLandMine; + } + + public static Cell of(boolean isLandMine) { + return new Cell(isLandMine); + } +} diff --git a/src/main/java/cleancode/minesweeper/tobe/MinesweeperGame.java b/src/main/java/cleancode/minesweeper/tobe/MinesweeperGame.java index dd85c3ce0..74e915929 100644 --- a/src/main/java/cleancode/minesweeper/tobe/MinesweeperGame.java +++ b/src/main/java/cleancode/minesweeper/tobe/MinesweeperGame.java @@ -1,187 +1,167 @@ package cleancode.minesweeper.tobe; +import cleancode.minesweeper.tobe.io.InputHandler; +import cleancode.minesweeper.tobe.io.OutputHandler; + import java.util.Random; import java.util.Scanner; public class MinesweeperGame { - private static String[][] board = new String[8][10]; - private static Integer[][] landMineCounts = new Integer[8][10]; - private static boolean[][] landMines = new boolean[8][10]; + + public static final int COLUMN_COUNT = 8; + public static final int ROW_COUNT = 10; + public static final int LAND_MINE_COUNT = 10; + private static final InputHandler inputHandler = new InputHandler(); + private static final OutputHandler outputHandler = new OutputHandler(); + private static final Cell[][] board = new Cell[COLUMN_COUNT][ROW_COUNT]; private static int gameStatus = 0; // 0: 게임 중, 1: 승리, -1: 패배 + public static void main(String[] args) { - System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - System.out.println("지뢰찾기 게임 시작!"); - System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); - Scanner scanner = new Scanner(System.in); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 10; j++) { - board[i][j] = "□"; + initializeBoard(); + gameStart(); + } + + private static void gameStart() { + outputHandler.showStartMessage(); + while (true) { + outputHandler.showBoard(board); + if (isGameOver()) break; + System.out.println(); + Coordinates coordinates = getCoordinates(); + getUserActionFor(coordinates); + } + } + + private static void initializeBoard() { + for (int col = 0; col < COLUMN_COUNT; col++) { + for (int row = 0; row < ROW_COUNT; row++) { + board[col][row] = Cell.of(false); } } - for (int i = 0; i < 10; i++) { - int col = new Random().nextInt(10); - int row = new Random().nextInt(8); - landMines[row][col] = true; + for (int i = 0; i < LAND_MINE_COUNT; i++) { + int col = new Random().nextInt(COLUMN_COUNT); + int row = new Random().nextInt(ROW_COUNT); + board[col][row] = Cell.of(true); } - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 10; j++) { + for (int col = 0; col < COLUMN_COUNT; col++) { + for (int row = 0; row < ROW_COUNT; row++) { int count = 0; - if (!landMines[i][j]) { - if (i - 1 >= 0 && j - 1 >= 0 && landMines[i - 1][j - 1]) { + Cell cell = board[col][row]; + if (!cell.isLandMine()) { + if (col - 1 >= 0 && row - 1 >= 0 && board[col - 1][row - 1].isLandMine()) { count++; } - if (i - 1 >= 0 && landMines[i - 1][j]) { + if (col - 1 >= 0 && board[col - 1][row].isLandMine()) { count++; } - if (i - 1 >= 0 && j + 1 < 10 && landMines[i - 1][j + 1]) { + if (col - 1 >= 0 && row + 1 < ROW_COUNT && board[col - 1][row + 1].isLandMine()) { count++; } - if (j - 1 >= 0 && landMines[i][j - 1]) { + if (row - 1 >= 0 && board[col][row - 1].isLandMine()) { count++; } - if (j + 1 < 10 && landMines[i][j + 1]) { + if (row + 1 < ROW_COUNT && board[col][row + 1].isLandMine()) { count++; } - if (i + 1 < 8 && j - 1 >= 0 && landMines[i + 1][j - 1]) { + if (col + 1 < COLUMN_COUNT && row - 1 >= 0 && board[col + 1][row - 1].isLandMine()) { count++; } - if (i + 1 < 8 && landMines[i + 1][j]) { + if (col + 1 < COLUMN_COUNT && board[col + 1][row].isLandMine()) { count++; } - if (i + 1 < 8 && j + 1 < 10 && landMines[i + 1][j + 1]) { + if (col + 1 < COLUMN_COUNT && row + 1 < ROW_COUNT && board[col + 1][row + 1].isLandMine()) { count++; } - landMineCounts[i][j] = count; - continue; + cell.applyLandMineCount(count); } - landMineCounts[i][j] = 0; } } - while (true) { - System.out.println(" a b c d e f g h i j"); - for (int i = 0; i < 8; i++) { - System.out.printf("%d ", i + 1); - for (int j = 0; j < 10; j++) { - System.out.print(board[i][j] + " "); - } - System.out.println(); - } - if (gameStatus == 1) { - System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!"); - break; - } - if (gameStatus == -1) { - System.out.println("지뢰를 밟았습니다. GAME OVER!"); - break; - } - System.out.println(); - System.out.println("선택할 좌표를 입력하세요. (예: a1)"); - String input = scanner.nextLine(); - System.out.println("선택한 셀에 대한 행위를 선택하세요. (1: 오픈, 2: 깃발 꽂기)"); - String input2 = scanner.nextLine(); - char c = input.charAt(0); - char r = input.charAt(1); - int col; - switch (c) { - case 'a': - col = 0; - break; - case 'b': - col = 1; - break; - case 'c': - col = 2; - break; - case 'd': - col = 3; - break; - case 'e': - col = 4; - break; - case 'f': - col = 5; - break; - case 'g': - col = 6; - break; - case 'h': - col = 7; - break; - case 'i': - col = 8; - break; - case 'j': - col = 9; - break; - default: - col = -1; - break; - } - int row = Character.getNumericValue(r) - 1; - if (input2.equals("2")) { - board[row][col] = "⚑"; - boolean open = true; - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 10; j++) { - if (board[i][j].equals("□")) { - open = false; - } - } - } - if (open) { - gameStatus = 1; - } - } else if (input2.equals("1")) { - if (landMines[row][col]) { - board[row][col] = "☼"; - gameStatus = -1; - continue; - } else { - open(row, col); - } - boolean open = true; - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 10; j++) { - if (board[i][j].equals("□")) { - open = false; - } - } - } - if (open) { - gameStatus = 1; - } - } else { - System.out.println("잘못된 번호를 선택하셨습니다."); - } + } + + + private static void getUserActionFor(Coordinates coordinates) { + String input2 = inputHandler.getUserActionInput(); + if (input2.equals("2")) { + flagOn(coordinates); + } else if (input2.equals("1")) { + openAt(coordinates); + } else { + outputHandler.showInvalidInputError(); } } - private static void open(int row, int col) { - if (row < 0 || row >= 8 || col < 0 || col >= 10) { + + private static void openAt(Coordinates coordinates) { + Cell cell = board[coordinates.row()][coordinates.col()]; + cell.open(); + if (cell.isLandMine()) { + gameStatus = -1; return; + } else { + openAt(coordinates.row(), coordinates.col()); } - if (!board[row][col].equals("□")) { - return; + gameStatus = getWinningStatus(); + } + + private static void flagOn(Coordinates coordinates) { + Cell cell = board[coordinates.row()][coordinates.col()]; + cell.flag(); + gameStatus = getWinningStatus(); + } + + private static int getWinningStatus() { + for (int col = 0; col < COLUMN_COUNT; col++) { + for (int row = 0; row < ROW_COUNT; row++) { + if (board[col][row].isChecked()) { + return 0; + } + } } - if (landMines[row][col]) { - return; + return 1; + } + + + private static Coordinates getCoordinates() { + String input = inputHandler.getCoordinatesInput(); + int c = input.charAt(0) - 'a'; + char r = input.charAt(1); + int row = Character.getNumericValue(r) - 1; + return new Coordinates(c, row); + } + + + private record Coordinates(int col, int row) { + } + + private static boolean isGameOver() { + if (gameStatus == 1) { + outputHandler.showGameClearMessage(); + return true; + } + if (gameStatus == -1) { + outputHandler.showGameOverMessage(); + return true; } - if (landMineCounts[row][col] != 0) { - board[row][col] = String.valueOf(landMineCounts[row][col]); + return false; + } + + private static void openAt(int row, int col) { + if (row < 0 || row >= ROW_COUNT || col < 0 || col >= COLUMN_COUNT) { return; - } else { - board[row][col] = "■"; } - open(row - 1, col - 1); - open(row - 1, col); - open(row - 1, col + 1); - open(row, col - 1); - open(row, col + 1); - open(row + 1, col - 1); - open(row + 1, col); - open(row + 1, col + 1); + Cell cell = board[col][row]; + if (cell.isLandMine() || cell.isChecked()) return; + cell.open(); + openAt(row - 1, col - 1); + openAt(row - 1, col); + openAt(row - 1, col + 1); + openAt(row, col - 1); + openAt(row, col + 1); + openAt(row + 1, col - 1); + openAt(row + 1, col); + openAt(row + 1, col + 1); } } diff --git a/src/main/java/cleancode/minesweeper/tobe/io/InputHandler.java b/src/main/java/cleancode/minesweeper/tobe/io/InputHandler.java new file mode 100644 index 000000000..01a99b7f1 --- /dev/null +++ b/src/main/java/cleancode/minesweeper/tobe/io/InputHandler.java @@ -0,0 +1,16 @@ +package cleancode.minesweeper.tobe.io; + +import java.util.Scanner; + +public class InputHandler { + private Scanner scanner = new Scanner(System.in); + public String getUserActionInput() { + System.out.println("선택한 셀에 대한 행위를 선택하세요. (1: 오픈, 2: 깃발 꽂기)"); + return scanner.nextLine(); + } + + public String getCoordinatesInput() { + System.out.println("선택할 좌표를 입력하세요. (예: a1)"); + return scanner.nextLine(); + } +} diff --git a/src/main/java/cleancode/minesweeper/tobe/io/OutputHandler.java b/src/main/java/cleancode/minesweeper/tobe/io/OutputHandler.java new file mode 100644 index 000000000..2961dd3bd --- /dev/null +++ b/src/main/java/cleancode/minesweeper/tobe/io/OutputHandler.java @@ -0,0 +1,30 @@ +package cleancode.minesweeper.tobe.io; + +import cleancode.minesweeper.tobe.Cell; + +public class OutputHandler { + public void showInvalidInputError() { + System.out.println("잘못된 번호를 선택하셨습니다."); + } + public void showGameOverMessage() { + System.out.println("지뢰를 밟았습니다. GAME OVER!"); + } + public void showGameClearMessage() { + System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!"); + } + public void showStartMessage() { + System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + System.out.println("지뢰찾기 게임 시작!"); + System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + } + public void showBoard(Cell[][] board) { + System.out.println(" a b c d e f g h i j"); + for (int col = 0; col < board.length; col++) { + System.out.printf("%d ", col + 1); + for (int row = 0; row < board[0].length; row++) { + System.out.print(board[col][row] + " "); + } + System.out.println(); + } + } +}