描述:用戶輸入二維雷區的高和寬,輸入確定地雷數,隨機在地雷區生成地雷。用戶輸入橫豎坐標進行挖雷,挖到地雷游戲以失敗結束,并讓用戶選擇是否再次游戲;沒挖到雷,顯示該區域8個方向地雷數。如果8個方向都沒有地雷,即地雷數為0,自動挖開周圍區域,如果周圍區域挖開后地雷數任為0繼續自動挖開周圍區域直到地雷數不為0為止。當剩下未挖開區域為地雷即游戲成功結束。
最終實現效果:
?思路
1.用二維數組表示掃雷的區域,其中長寬我們可以自己定義,埋雷的數量也可以自定義,但是為了游戲的可玩性,設計雷數量小于掃雷整個區域格子的34%。
2.因為挖開的格子要顯示周圍埋雷的數量,所以整個掃雷區域的數組用int類型,并且定義當某個格子為-1時,則為雷。
3.游戲結束的條件---》成功或者失敗就會結束游戲。成功的條件為挖開所有安全的格子并且不踩雷,失敗的條件為踩雷。踩雷很好判斷,即判斷選中的格子在二維數組中的值為不為-1,-1則為踩雷。要判斷成功的條件,還得定義一個變量表示未挖的格子數,當它為0時即為成功。
4.需要一個布爾型的二維數組表示每個格子是否挖開與否。
具體實現
變量定義:
private static int[][] mineField; // 雷區二維數組private static boolean[][] revealed; // 表示每個位置是否被挖開,true表示挖開,false表示未挖開private static int rows; // 表示行private static int cols; // 表示列private static int mineCount; // 表示雷區總數private static int cellsLeft; // 表示未挖開的安全的格子數
游戲菜單:
public static void menu(){Scanner scanner = new Scanner(System.in);System.out.println("**************挖地雷游戲開始**************");System.out.print("請輸入雷區的高度:");rows = scanner.nextInt();System.out.print("請輸入雷區的寬度:");cols = scanner.nextInt();// 計算最大允許的地雷數量int maxMines = (int) (rows * cols * 0.34);System.out.print("請輸入地雷數(小于" + maxMines + "個):");mineCount = scanner.nextInt();// 檢查地雷數量是否超過限制while (mineCount >= maxMines || mineCount <= 0) {System.out.print("地雷數不能超過最大限制且必須大于0,請重新輸入地雷數(小于" + maxMines + "個):");mineCount = scanner.nextInt();}cellsLeft = rows * cols - mineCount; // 初始化為挖開的安全的格子數System.out.println("地雷已經埋好,挖雷開始!");}
main:
public static void main(String[] args) {Scanner scanner = new Scanner(System.in);boolean playAgain; // 是否再次游戲do {menu();initializeGame(); // 初始化游戲boolean gameLost = false; // 標識是否踩雷的狀態 默認為沒有踩雷while (cellsLeft > 0 && !gameLost) { // 當未挖開的安全格子數大于0 或者 沒有踩雷printField(); // 打印圖形int x, y;do {System.out.print("請輸入挖雷的x坐標(0-" + (rows - 1) + "):");x = scanner.nextInt();System.out.print("請輸入挖雷的y坐標(0-" + (cols - 1) + "):");y = scanner.nextInt();if (x < 0 || x >= rows || y < 0 || y >= cols) {System.out.println("輸入超出范圍,請重新輸入!");} else if (revealed[x][y]) {System.out.println("這個位置已經挖過了,請重新輸入!");}} while (x < 0 || x >= rows || y < 0 || y >= cols || revealed[x][y]);System.out.println("你挖雷的坐標是("+ x + "," + y + ")!");if (mineField[x][y] == -1) {revealed[x][y] = true;printField();System.out.println("你踩到地雷了!游戲失敗!");gameLost = true;} else {revealCell(x, y); // 遞歸挖格子}}if (!gameLost) {System.out.println("恭喜你,游戲成功!");}System.out.print("你想再玩一次嗎?(輸入true繼續,輸入false結束):");playAgain = scanner.nextBoolean();} while (playAgain);scanner.close();}
初始化游戲:initializeGame(); 方法中包括初始化了掃雷區域二維數組的長寬,以及記錄是否被挖開的布爾型數組的長寬。調用placeMines()方法隨機設置了地雷。調用calculateNumbers()方法計算每個非地雷格子周圍的地雷數。
具體如下:
private static void initializeGame() {mineField = new int[rows][cols];revealed = new boolean[rows][cols];placeMines(); // 放地雷calculateNumbers(); // 計算每個非地雷格子周圍的地雷數}private static void placeMines() {Random random = new Random();int minesPlaced = 0;while (minesPlaced < mineCount) {int x = random.nextInt(rows);int y = random.nextInt(cols);if (mineField[x][y] != -1) { // 必須要當前格子沒有放雷才行,否則重復放入了mineField[x][y] = -1;minesPlaced++;}}}private static void calculateNumbers() {// 遍歷整個雷區,對于每個非地雷格子,檢查其周圍八個方向的格子 --> 如果周圍有地雷,則計數并更新該格子的值。for (int x = 0; x < rows; x++) {for (int y = 0; y < cols; y++) {if (mineField[x][y] == -1) continue;int mineCount = 0;for (int dx = -1; dx <= 1; dx++) {for (int dy = -1; dy <= 1; dy++) {int nx = x + dx;int ny = y + dy;if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && mineField[nx][ny] == -1) {mineCount++;}}}mineField[x][y] = mineCount;}}}
其中dx和dy都表示偏移量,表示該格子周圍的八個格子。這八個格子中有埋雷的格子就讓mineCount++,最終得到該格子的值。
初始化游戲完畢后開始選擇要挖的格子,格子的x坐標和y坐標不能超過整個掃雷區域的寬和長,并且不能是挖過的格子,否則重新輸入有效的x和y:
do {System.out.print("請輸入挖雷的x坐標(0-" + (rows - 1) + "):");x = scanner.nextInt();System.out.print("請輸入挖雷的y坐標(0-" + (cols - 1) + "):");y = scanner.nextInt();if (x < 0 || x >= rows || y < 0 || y >= cols) {System.out.println("輸入超出范圍,請重新輸入!");} else if (revealed[x][y]) {System.out.println("這個位置已經挖過了,請重新輸入!");}} while (x < 0 || x >= rows || y < 0 || y >= cols || revealed[x][y]);
輸入有效的x和y后,判斷當前挖開的格子是否埋雷,即判斷 mineField[x][y] == -1,如果為true則游戲失敗,如果不為true則遞歸挖開格子,直到格子周圍埋雷數量大于0。
遞歸挖開格子的方法為:
private static void revealCell(int x, int y) {if (x < 0 || x >= rows || y < 0 || y >= cols || revealed[x][y]) { // 結束條件return;}revealed[x][y] = true;cellsLeft--;if (mineField[x][y] == 0) {for (int dx = -1; dx <= 1; dx++) {for (int dy = -1; dy <= 1; dy++) {revealCell(x + dx, y + dy);}}}}
打印圖形的方法printField():
private static void printField() {for (int x = 0; x < rows; x++) {for (int y = 0; y < cols; y++) {if (revealed[x][y]) {if (mineField[x][y] == -1) {System.out.print("* ");} else {System.out.print(mineField[x][y] + " ");}} else {System.out.print("\u25A0 ");}}System.out.println();}}
整體代碼
import java.util.Random;
import java.util.Scanner;public class Game {private static int[][] mineField; // 雷區二維數組private static boolean[][] revealed; // 表示每個位置是否被挖開,true表示挖開,false表示未挖開private static int rows; // 表示行private static int cols; // 表示列private static int mineCount; // 表示雷區總數private static int cellsLeft; // 表示未挖開的安全的格子數public static void main(String[] args) {Scanner scanner = new Scanner(System.in);boolean playAgain; // 是否再次游戲do {menu();initializeGame(); // 初始化游戲boolean gameLost = false; // 標識是否踩雷的狀態 默認為沒有踩雷while (cellsLeft > 0 && !gameLost) { // 當未挖開的安全格子數大于0 或者 沒有踩雷printField(); // 打印圖形int x, y;do {System.out.print("請輸入挖雷的x坐標(0-" + (rows - 1) + "):");x = scanner.nextInt();System.out.print("請輸入挖雷的y坐標(0-" + (cols - 1) + "):");y = scanner.nextInt();if (x < 0 || x >= rows || y < 0 || y >= cols) {System.out.println("輸入超出范圍,請重新輸入!");} else if (revealed[x][y]) {System.out.println("這個位置已經挖過了,請重新輸入!");}} while (x < 0 || x >= rows || y < 0 || y >= cols || revealed[x][y]);System.out.println("你挖雷的坐標是("+ x + "," + y + ")!");if (mineField[x][y] == -1) {revealed[x][y] = true;printField();System.out.println("你踩到地雷了!游戲失敗!");gameLost = true;} else {revealCell(x, y); // 遞歸挖格子}}if (!gameLost) {System.out.println("恭喜你,游戲成功!");}System.out.print("你想再玩一次嗎?(輸入true繼續,輸入false結束):");playAgain = scanner.nextBoolean();} while (playAgain);scanner.close();}public static void menu(){Scanner scanner = new Scanner(System.in);System.out.println("**************挖地雷游戲開始**************");System.out.print("請輸入雷區的高度:");rows = scanner.nextInt();System.out.print("請輸入雷區的寬度:");cols = scanner.nextInt();// 計算最大允許的地雷數量int maxMines = (int) (rows * cols * 0.34);System.out.print("請輸入地雷數(小于" + maxMines + "個):");mineCount = scanner.nextInt();// 檢查地雷數量是否超過限制while (mineCount >= maxMines || mineCount <= 0) {System.out.print("地雷數不能超過最大限制且必須大于0,請重新輸入地雷數(小于" + maxMines + "個):");mineCount = scanner.nextInt();}cellsLeft = rows * cols - mineCount; // 初始化為挖開的安全的格子數System.out.println("地雷已經埋好,挖雷開始!");}// 初始化游戲的方法private static void initializeGame() {mineField = new int[rows][cols];revealed = new boolean[rows][cols];placeMines(); // 放地雷calculateNumbers(); // 計算每個非地雷格子周圍的地雷數}private static void placeMines() {Random random = new Random();int minesPlaced = 0;while (minesPlaced < mineCount) {int x = random.nextInt(rows);int y = random.nextInt(cols);if (mineField[x][y] != -1) { // 必須要當前格子沒有放雷才行,否則重復放入了mineField[x][y] = -1;minesPlaced++;}}}private static void calculateNumbers() {// 遍歷整個雷區,對于每個非地雷格子,檢查其周圍八個方向的格子 --> 如果周圍有地雷,則計數并更新該格子的值。for (int x = 0; x < rows; x++) {for (int y = 0; y < cols; y++) {if (mineField[x][y] == -1) continue;int mineCount = 0;for (int dx = -1; dx <= 1; dx++) {for (int dy = -1; dy <= 1; dy++) {int nx = x + dx;int ny = y + dy;if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && mineField[nx][ny] == -1) {mineCount++;}}}mineField[x][y] = mineCount;}}}private static void revealCell(int x, int y) {if (x < 0 || x >= rows || y < 0 || y >= cols || revealed[x][y]) { // 結束條件return;}revealed[x][y] = true;cellsLeft--;if (mineField[x][y] == 0) {for (int dx = -1; dx <= 1; dx++) {for (int dy = -1; dy <= 1; dy++) {revealCell(x + dx, y + dy);}}}}private static void printField() {for (int x = 0; x < rows; x++) {for (int y = 0; y < cols; y++) {if (revealed[x][y]) {if (mineField[x][y] == -1) {System.out.print("* ");} else {System.out.print(mineField[x][y] + " ");}} else {System.out.print("\u25A0 ");}}System.out.println();}}
}