강사님이 최대한 더럽고 시간복잡도가 높은 최악의 코드를 골라오셨고, 우리는 이번 시간을 통해 이 코드를 읽기 좋은 코드로 거듭나도록 했다.
먼저 원래 코드는 이렇다.
Original Code
package cleancode.minesweeper.asis;
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];
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] = "□";
}
}
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 < 8; i++) {
for (int j = 0; j < 10; j++) {
int count = 0;
if (!landMines[i][j]) {
if (i - 1 >= 0 && j - 1 >= 0 && landMines[i - 1][j - 1]) {
count++;
}
if (i - 1 >= 0 && landMines[i - 1][j]) {
count++;
}
if (i - 1 >= 0 && j + 1 < 10 && landMines[i - 1][j + 1]) {
count++;
}
if (j - 1 >= 0 && landMines[i][j - 1]) {
count++;
}
if (j + 1 < 10 && landMines[i][j + 1]) {
count++;
}
if (i + 1 < 8 && j - 1 >= 0 && landMines[i + 1][j - 1]) {
count++;
}
if (i + 1 < 8 && landMines[i + 1][j]) {
count++;
}
if (i + 1 < 8 && j + 1 < 10 && landMines[i + 1][j + 1]) {
count++;
}
landMineCounts[i][j] = count;
continue;
}
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 open(int row, int col) {
if (row < 0 || row >= 8 || col < 0 || col >= 10) {
return;
}
if (!board[row][col].equals("□")) {
return;
}
if (landMines[row][col]) {
return;
}
if (landMineCounts[row][col] != 0) {
board[row][col] = String.valueOf(landMineCounts[row][col]);
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);
}
}
예를 들어, for loop에서 단순히 i, j로 두던 것을 row, col로 바꾸는 등의 refactoring을 진행했다.
Refactoring Variable
package cleancode.minesweeper.asis;
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];
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] = "□";
// }
// }
//수정 사항: 변수 이름 직관적으로 짓기
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
board[row][col] = "□";
}
}
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 row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
int count = 0;
if (!landMines[row][col]) {
if (row - 1 >= 0 && col - 1 >= 0 && landMines[row - 1][col - 1]) {
count++;
}
if (row - 1 >= 0 && landMines[row - 1][col]) {
count++;
}
if (row - 1 >= 0 && col + 1 < 10 && landMines[row - 1][col + 1]) {
count++;
}
if (col - 1 >= 0 && landMines[row][col - 1]) {
count++;
}
if (col + 1 < 10 && landMines[row][col + 1]) {
count++;
}
if (row + 1 < 8 && col - 1 >= 0 && landMines[row + 1][col - 1]) {
count++;
}
if (row + 1 < 8 && landMines[row + 1][col]) {
count++;
}
if (row + 1 < 8 && col + 1 < 10 && landMines[row + 1][col + 1]) {
count++;
}
landMineCounts[row][col] = count;
continue;
}
landMineCounts[row][col] = 0;
}
}
while (true) {
System.out.println(" a b c d e f g h i j");
for (int row = 0; row < 8; row++) {
System.out.printf("%d ", row + 1);
for (int col = 0; col < 10; col++) {
System.out.print(board[row][col] + " ");
}
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 cellInput = scanner.nextLine();
System.out.println("선택한 셀에 대한 행위를 선택하세요. (1: 오픈, 2: 깃발 꽂기)");
String userActionInput = scanner.nextLine();
char cellInputCol = cellInput.charAt(0);
char cellInputRow = cellInput.charAt(1);
int selectedColIndex;
switch (cellInputCol) {
case 'a':
selectedColIndex = 0;
break;
case 'b':
selectedColIndex = 1;
break;
case 'c':
selectedColIndex = 2;
break;
case 'd':
selectedColIndex = 3;
break;
case 'e':
selectedColIndex = 4;
break;
case 'f':
selectedColIndex = 5;
break;
case 'g':
selectedColIndex = 6;
break;
case 'h':
selectedColIndex = 7;
break;
case 'i':
selectedColIndex = 8;
break;
case 'j':
selectedColIndex = 9;
break;
default:
selectedColIndex = -1;
break;
}
int selectedRowIndex = Character.getNumericValue(cellInputRow) - 1;
if (userActionInput.equals("2")) {
board[selectedRowIndex][selectedColIndex] = "⚑";
boolean isAllOpened = true;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
if (board[row][col].equals("□")) {
isAllOpened = false;
}
}
}
if (isAllOpened) {
gameStatus = 1;
}
} else if (userActionInput.equals("1")) {
if (landMines[selectedRowIndex][selectedColIndex]) {
board[selectedRowIndex][selectedColIndex] = "☼";
gameStatus = -1;
continue;
} else {
open(selectedRowIndex, selectedColIndex);
}
boolean isAllOpened = true;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
if (board[row][col].equals("□")) {
isAllOpened = false;
}
}
}
if (isAllOpened) {
gameStatus = 1;
}
} else {
System.out.println("잘못된 번호를 선택하셨습니다.");
}
}
}
private static void open(int row, int col) {
if (row < 0 || row >= 8 || col < 0 || col >= 10) {
return;
}
if (!board[row][col].equals("□")) {
return;
}
if (landMines[row][col]) {
return;
}
if (landMineCounts[row][col] != 0) {
board[row][col] = String.valueOf(landMineCounts[row][col]);
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);
}
}
한 가지를 실행하는데 집중한다. 코드를 읽고 이 메서드가 하는 일이 여러 개라면 작은 메서드로 나누는 게 좋다. 기본적이지만 처음엔 어려웠던 부분인데 다시 짚고 넘어가봐서 좋았다.
사용하는 입장에서도 더 편하게 쓸 수 있고, 후손 개발자 입장에서도 어떤 것을 넣어야하는 변수인지 알기 쉽다.
package cleancode.minesweeper.asis;
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];
private static int gameStatus = 0; // 0: 게임 중, 1: 승리, -1: 패배
public static void main(String[] args) {
showGameStartComments();
Scanner scanner = new Scanner(System.in);
initializeGame();
while (true) {
showBoard();
if (gameStatus == 1) {
System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");
break;
}
if (gameStatus == -1) {
System.out.println("지뢰를 밟았습니다. GAME OVER!");
break;
}
System.out.println("선택할 좌표를 입력하세요. (예: a1)");
String cellInput = scanner.nextLine();
System.out.println("선택한 셀에 대한 행위를 선택하세요. (1: 오픈, 2: 깃발 꽂기)");
String userActionInput = scanner.nextLine();
char cellInputCol = cellInput.charAt(0);
char cellInputRow = cellInput.charAt(1);
int selectedColIndex = convertColFrom(cellInputCol);
int selectedRowIndex = convertRowFrom(cellInputRow);
if (userActionInput.equals("2")) {
board[selectedRowIndex][selectedColIndex] = "⚑";
checkIfGameIsOver();
} else if (userActionInput.equals("1")) {
if (landMines[selectedRowIndex][selectedColIndex]) {
board[selectedRowIndex][selectedColIndex] = "☼";
gameStatus = -1;
continue;
} else {
open(selectedRowIndex, selectedColIndex);
}
checkIfGameIsOver();
} else {
System.out.println("잘못된 번호를 선택하셨습니다.");
}
}
}
private static void checkIfGameIsOver() {
boolean isAllOpened = isAllCellOpened();
if (isAllOpened) {
gameStatus = 1;
}
}
private static boolean isAllCellOpened() {
boolean isAllOpened = true;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
if (board[row][col].equals("□")) {
isAllOpened = false;
}
}
}
return isAllOpened;
}
private static int convertRowFrom(char cellInputRow) {
return Character.getNumericValue(cellInputRow) - 1;
}
private static int convertColFrom(char cellInputCol) {
switch (cellInputCol) {
case 'a':
// selectedColIndex = 0;
// break;
return 0;
case 'b':
return 1;
case 'c':
return 2;
case 'd':
return 3;
case 'e':
return 4;
case 'f':
return 5;
case 'g':
return 6;
case 'h':
return 7;
case 'i':
return 8;
case 'j':
return 9;
default:
return -1;
}
}
private static void showBoard() {
System.out.println(" a b c d e f g h i j");
for (int row = 0; row < 8; row++) {
System.out.printf("%d ", row + 1);
for (int col = 0; col < 10; col++) {
System.out.print(board[row][col] + " ");
}
System.out.println();
}
System.out.println();
}
private static void initializeGame() {
//수정 사항: 변수 이름 직관적으로 짓기
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
board[row][col] = "□";
}
}
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 row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
int count = 0;
if (!landMines[row][col]) {
if (row - 1 >= 0 && col - 1 >= 0 && landMines[row - 1][col - 1]) {
count++;
}
if (row - 1 >= 0 && landMines[row - 1][col]) {
count++;
}
if (row - 1 >= 0 && col + 1 < 10 && landMines[row - 1][col + 1]) {
count++;
}
if (col - 1 >= 0 && landMines[row][col - 1]) {
count++;
}
if (col + 1 < 10 && landMines[row][col + 1]) {
count++;
}
if (row + 1 < 8 && col - 1 >= 0 && landMines[row + 1][col - 1]) {
count++;
}
if (row + 1 < 8 && landMines[row + 1][col]) {
count++;
}
if (row + 1 < 8 && col + 1 < 10 && landMines[row + 1][col + 1]) {
count++;
}
landMineCounts[row][col] = count;
continue;
}
landMineCounts[row][col] = 0;
}
}
}
private static void showGameStartComments() {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println("지뢰찾기 게임 시작!");
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
private static void open(int row, int col) {
if (row < 0 || row >= 8 || col < 0 || col >= 10) {
return;
}
if (!board[row][col].equals("□")) {
return;
}
if (landMines[row][col]) {
return;
}
if (landMineCounts[row][col] != 0) {
board[row][col] = String.valueOf(landMineCounts[row][col]);
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);
}
}
method를 추출한다는 것 자체가 외부 세계와 내부 세계의 경계를 만든다는 뜻이다. 하나의 세계 안에서는 추상화 레벨이 동등해야 한다.
추상화 레벨이 맞지 않아 일어나는 문제가 꽤나 잘 들어난다.
예를 들면,
이렇게 추상화 레벨이 맞지 않는 상황이 나타나면 클린코드라 하기 어렵다.
이런식으로 바꿔야 한다는 뜻이다.
package cleancode.minesweeper.asis;
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];
private static int gameStatus = 0; // 0: 게임 중, 1: 승리, -1: 패배
public static void main(String[] args) {
showGameStartComments();
Scanner scanner = new Scanner(System.in);
initializeGame();
while (true) {
showBoard();
if (doesUserWinTheGame()) {
System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");
break;
}
if (doesUserLooseTheGame()) {
System.out.println("지뢰를 밟았습니다. GAME OVER!");
break;
}
String cellInput = getCellInputFromUser(scanner);
String userActionInput = getUserActionInputFromUser(scanner);
int selectedColIndex = getSelectedColIndex(cellInput);
int selectedRowIndex = getSelectedRowIndex(cellInput);
if (doesUserChooseFlag(userActionInput)) {
board[selectedRowIndex][selectedColIndex] = "⚑";
checkIfGameIsOver();
}
else if (doesUserChooseOpen(userActionInput)) {
if (isLandMineCell(selectedRowIndex, selectedColIndex)) {
board[selectedRowIndex][selectedColIndex] = "☼";
changeGameStatusToLoose();
continue;
} else {
open(selectedRowIndex, selectedColIndex);
}
checkIfGameIsOver();
} else {
System.out.println("잘못된 번호를 선택하셨습니다.");
}
}
}
private static void changeGameStatusToLoose() {
gameStatus = -1;
}
private static boolean isLandMineCell(int selectedRowIndex, int selectedColIndex) {
return landMines[selectedRowIndex][selectedColIndex];
}
private static boolean doesUserChooseOpen(String userActionInput) {
return userActionInput.equals("1");
}
private static boolean doesUserChooseFlag(String userActionInput) {
return userActionInput.equals("2");
}
private static int getSelectedRowIndex(String cellInput) {
char cellInputRow = cellInput.charAt(1);
return convertRowFrom(cellInputRow);
}
private static int getSelectedColIndex(String cellInput) {
char cellInputCol = cellInput.charAt(0);
return convertColFrom(cellInputCol);
}
private static String getUserActionInputFromUser(Scanner scanner) {
System.out.println("선택한 셀에 대한 행위를 선택하세요. (1: 오픈, 2: 깃발 꽂기)");
return scanner.nextLine();
}
private static String getCellInputFromUser(Scanner scanner) {
System.out.println("선택할 좌표를 입력하세요. (예: a1)");
return scanner.nextLine();
}
private static boolean doesUserLooseTheGame() {
return gameStatus == -1;
}
private static boolean doesUserWinTheGame() {
return gameStatus == 1;
}
private static void checkIfGameIsOver() {
boolean isAllOpened = isAllCellOpened();
if (isAllOpened) {
changeGameStatusToWin();
}
}
private static void changeGameStatusToWin() {
gameStatus = 1;
}
private static boolean isAllCellOpened() {
boolean isAllOpened = true;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
if (board[row][col].equals("□")) {
isAllOpened = false;
}
}
}
return isAllOpened;
}
private static int convertRowFrom(char cellInputRow) {
return Character.getNumericValue(cellInputRow) - 1;
}
private static int convertColFrom(char cellInputCol) {
switch (cellInputCol) {
case 'a':
// selectedColIndex = 0;
// break;
return 0;
case 'b':
return 1;
case 'c':
return 2;
case 'd':
return 3;
case 'e':
return 4;
case 'f':
return 5;
case 'g':
return 6;
case 'h':
return 7;
case 'i':
return 8;
case 'j':
return 9;
default:
return -1;
}
}
private static void showBoard() {
System.out.println(" a b c d e f g h i j");
for (int row = 0; row < 8; row++) {
System.out.printf("%d ", row + 1);
for (int col = 0; col < 10; col++) {
System.out.print(board[row][col] + " ");
}
System.out.println();
}
System.out.println();
}
private static void initializeGame() {
//수정 사항: 변수 이름 직관적으로 짓기
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
board[row][col] = "□";
}
}
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 row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
int count = 0;
if (!isLandMineCell(row, col)) {
if (row - 1 >= 0 && col - 1 >= 0 && isLandMineCell(row - 1, col - 1)) {
count++;
}
if (row - 1 >= 0 && isLandMineCell(row - 1, col)) {
count++;
}
if (row - 1 >= 0 && col + 1 < 10 && isLandMineCell(row - 1, col + 1)) {
count++;
}
if (col - 1 >= 0 && isLandMineCell(row, col - 1)) {
count++;
}
if (col + 1 < 10 && isLandMineCell(row, col + 1)) {
count++;
}
if (row + 1 < 8 && col - 1 >= 0 && isLandMineCell(row + 1, col - 1)) {
count++;
}
if (row + 1 < 8 && isLandMineCell(row + 1, col)) {
count++;
}
if (row + 1 < 8 && col + 1 < 10 && isLandMineCell(row + 1, col + 1)) {
count++;
}
landMineCounts[row][col] = count;
continue;
}
landMineCounts[row][col] = 0;
}
}
}
private static void showGameStartComments() {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println("지뢰찾기 게임 시작!");
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
private static void open(int row, int col) {
if (row < 0 || row >= 8 || col < 0 || col >= 10) {
return;
}
if (!board[row][col].equals("□")) {
return;
}
if (isLandMineCell(row, col)) {
return;
}
if (landMineCounts[row][col] != 0) {
board[row][col] = String.valueOf(landMineCounts[row][col]);
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);
}
}
자바의 convention에 맞게 변경한다.
package cleancode.minesweeper.asis;
import java.util.Random;
import java.util.Scanner;
public class MinesweeperGame {
public static final int BOARD_ROW_SIZE = 8;
public static final int BOARD_COL_SIZE = 10;
private static final String[][] BOARD = new String[BOARD_ROW_SIZE][BOARD_COL_SIZE];
private static final Integer[][] LAND_MINE_COUNTS = new Integer[BOARD_ROW_SIZE][BOARD_COL_SIZE];
private static final boolean[][] LAND_MINES = new boolean[BOARD_ROW_SIZE][BOARD_COL_SIZE];
private static final int LAND_MINE_COUNT = 10;
public static final String FLAG_SIGN = "⚑";
public static final String CLOSED_CELL_SIGN = "□";
public static final String OPENED_CELL_SIGN = "■";
private static int gameStatus = 0; // 0: 게임 중, 1: 승리, -1: 패배
public static void main(String[] args) {
showGameStartComments();
Scanner scanner = new Scanner(System.in);
initializeGame();
while (true) {
showBoard();
if (doesUserWinTheGame()) {
System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");
break;
}
if (doesUserLooseTheGame()) {
System.out.println("지뢰를 밟았습니다. GAME OVER!");
break;
}
String cellInput = getCellInputFromUser(scanner);
String userActionInput = getUserActionInputFromUser(scanner);
int selectedColIndex = getSelectedColIndex(cellInput);
int selectedRowIndex = getSelectedRowIndex(cellInput);
if (doesUserChooseFlag(userActionInput)) {
BOARD[selectedRowIndex][selectedColIndex] = FLAG_SIGN;
checkIfGameIsOver();
} else if (doesUserChooseOpen(userActionInput)) {
if (isLandMineCell(selectedRowIndex, selectedColIndex)) {
BOARD[selectedRowIndex][selectedColIndex] = "☼";
changeGameStatusToLoose();
continue;
} else {
open(selectedRowIndex, selectedColIndex);
}
checkIfGameIsOver();
} else {
System.out.println("잘못된 번호를 선택하셨습니다.");
}
}
}
private static void changeGameStatusToLoose() {
gameStatus = -1;
}
private static boolean isLandMineCell(int selectedRowIndex, int selectedColIndex) {
return LAND_MINES[selectedRowIndex][selectedColIndex];
}
private static boolean doesUserChooseOpen(String userActionInput) {
return userActionInput.equals("1");
}
private static boolean doesUserChooseFlag(String userActionInput) {
return userActionInput.equals("2");
}
private static int getSelectedRowIndex(String cellInput) {
char cellInputRow = cellInput.charAt(1);
return convertRowFrom(cellInputRow);
}
private static int getSelectedColIndex(String cellInput) {
char cellInputCol = cellInput.charAt(0);
return convertColFrom(cellInputCol);
}
private static String getUserActionInputFromUser(Scanner scanner) {
System.out.println("선택한 셀에 대한 행위를 선택하세요. (1: 오픈, 2: 깃발 꽂기)");
return scanner.nextLine();
}
private static String getCellInputFromUser(Scanner scanner) {
System.out.println("선택할 좌표를 입력하세요. (예: a1)");
return scanner.nextLine();
}
private static boolean doesUserLooseTheGame() {
return gameStatus == -1;
}
private static boolean doesUserWinTheGame() {
return gameStatus == 1;
}
private static void checkIfGameIsOver() {
boolean isAllOpened = isAllCellOpened();
if (isAllOpened) {
changeGameStatusToWin();
}
}
private static void changeGameStatusToWin() {
gameStatus = 1;
}
private static boolean isAllCellOpened() {
boolean isAllOpened = true;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 10; col++) {
if (BOARD[row][col].equals(CLOSED_CELL_SIGN)) {
isAllOpened = false;
}
}
}
return isAllOpened;
}
private static int convertRowFrom(char cellInputRow) {
return Character.getNumericValue(cellInputRow) - 1;
}
private static int convertColFrom(char cellInputCol) {
switch (cellInputCol) {
case 'a':
// selectedColIndex = 0;
// break;
return 0;
case 'b':
return 1;
case 'c':
return 2;
case 'd':
return 3;
case 'e':
return 4;
case 'f':
return 5;
case 'g':
return 6;
case 'h':
return 7;
case 'i':
return 8;
case 'j':
return 9;
default:
return -1;
}
}
private static void showBoard() {
System.out.println(" a b c d e f g h i j");
for (int row = 0; row < BOARD_ROW_SIZE; row++) {
System.out.printf("%d ", row + 1);
for (int col = 0; col < BOARD_COL_SIZE; col++) {
System.out.print(BOARD[row][col] + " ");
}
System.out.println();
}
System.out.println();
}
private static void initializeGame() {
//수정 사항: 변수 이름 직관적으로 짓기
for (int row = 0; row < BOARD_ROW_SIZE; row++) {
for (int col = 0; col < BOARD_COL_SIZE; col++) {
BOARD[row][col] = "□";
}
}
for (int i = 0; i < LAND_MINE_COUNT; i++) {
int col = new Random().nextInt(BOARD_COL_SIZE);
int row = new Random().nextInt(BOARD_ROW_SIZE);
LAND_MINES[row][col] = true;
}
for (int row = 0; row < BOARD_ROW_SIZE; row++) {
for (int col = 0; col < BOARD_COL_SIZE; col++) {
int count = 0;
if (!isLandMineCell(row, col)) {
if (row - 1 >= 0 && col - 1 >= 0 && isLandMineCell(row - 1, col - 1)) {
count++;
}
if (row - 1 >= 0 && isLandMineCell(row - 1, col)) {
count++;
}
if (row - 1 >= 0 && col + 1 < 10 && isLandMineCell(row - 1, col + 1)) {
count++;
}
if (col - 1 >= 0 && isLandMineCell(row, col - 1)) {
count++;
}
if (col + 1 < 10 && isLandMineCell(row, col + 1)) {
count++;
}
if (row + 1 < 8 && col - 1 >= 0 && isLandMineCell(row + 1, col - 1)) {
count++;
}
if (row + 1 < 8 && isLandMineCell(row + 1, col)) {
count++;
}
if (row + 1 < 8 && col + 1 < 10 && isLandMineCell(row + 1, col + 1)) {
count++;
}
LAND_MINE_COUNTS[row][col] = count;
continue;
}
LAND_MINE_COUNTS[row][col] = 0;
}
}
}
private static void showGameStartComments() {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println("지뢰찾기 게임 시작!");
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
private static void open(int row, int col) {
if (row < 0 || row >= BOARD_ROW_SIZE || col < 0 || col >= BOARD_COL_SIZE) {
return;
}
if (!BOARD[row][col].equals("□")) {
return;
}
if (isLandMineCell(row, col)) {
return;
}
if (LAND_MINE_COUNTS[row][col] != 0) {
BOARD[row][col] = String.valueOf(LAND_MINE_COUNTS[row][col]);
return;
} else {
BOARD[row][col] = OPENED_CELL_SIGN;
}
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);
}
}