Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
50 changes: 50 additions & 0 deletions src/main/java/cleancode/minesweeper/tobe/Cell.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
264 changes: 122 additions & 142 deletions src/main/java/cleancode/minesweeper/tobe/MinesweeperGame.java
Original file line number Diff line number Diff line change
@@ -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);
}

}
16 changes: 16 additions & 0 deletions src/main/java/cleancode/minesweeper/tobe/io/InputHandler.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
Loading