描述:用户输入二维雷区的高和宽,输入确定地雷数,随机在地雷区生成地雷。用户输入横竖坐标进行挖雷,挖到地雷游戏以失败结束,并让用户选择是否再次游戏;没挖到雷,显示该区域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();
}
}
}