Java控制台实现3x3数字拼图游戏
本文详解如何利用Java控制台开发3x3数字拼图游戏。通过二维数组管理棋盘,结合随机数打乱初始状态,并设计核心逻辑处理用户输入、合法性校验及邻接移动判断,最终实现通关检测。
项目目标
构建一个基于控制台的数字拼图程序,模拟经典滑块谜题的核心玩法。程序需在终端显示3x3的网格(其中一个位置为空),接受用户指令将相邻方块移入空位,并在所有方块归位时自动判定胜利。
核心数据结构与准备
整个游戏的状态由一个二维整型数组表示,其中1-8代表方块数字,9代表空白区域。为了实现交互,需要准备以下基础组件:
Scanner:用于读取控制台输入的指令。Random:用于在游戏开始前对棋盘进行合法打乱。int[][] grid:保存当前棋盘状态的矩阵变量。
关键功能模块设计
第1步:初始化与打乱局面
直接生成随机数字可能导致无法还原的局面,因此最佳实践是通过多次有效的“空白格交换”来模拟打乱过程,保证局面的可解性。
- 逻辑:记录空白格当前位置
(h, l)。 - 操作:重复100次操作,随机选择一个与空白格相邻的有效坐标
(x, y)并执行交换。 - 目的:确保最终生成的局面必定可以通过逆向步骤回到有序状态。
第2步:游戏主循环与画面渲染
游戏运行时应持续绘制界面并等待指令。打印函数需遍历数组,若检测到值9则输出空格以体现“缺失”效果,否则输出对应数字。
- 入口:主线程开始处调用
playGrame方法。 - 动作:在
while(true)死循环中先刷新屏幕,再获取用户输入,最后根据结果尝试更新棋盘。 - 状态:直到返回胜利标志时跳出循环。
第3步:输入校验与坐标定位
为保证用户体验,必须对用户的非法字符或越界操作进行拦截,并将抽象的“点击哪个数字”转化为具体的数组索引。
- 验证:检查输入是否为单个字符且范围在'1'-'8'之间,递归提示错误信息。
- 映射:扫描整个棋盘寻找该数字所在的
(row, col)坐标,将其赋值给全局坐标变量供后续逻辑使用。
第4步:合法性校验与位置交换
这是游戏逻辑的核心。只有当目标数字与空白格存在邻接关系时,才允许发生位移。
- 距离判断:计算两坐标点的曼哈顿距离,若行差与列差的绝对值之和为1,即视为相邻。
- 数据交换:将空白格中的值暂存,将目标值赋给空白格,再将原空白格值回填到目标位置。
- 更新标记:将全局空白格坐标
(h, l)同步至新位置。
第5步:胜利判定
每次交换后,系统需即时检查是否达成目标。通常采用顺序比对法:
- 从左上角开始,逐行逐列扫描数组元素。
- 按1至8的顺序核对,一旦发现不匹配立即终止并返回失败;若全部匹配且未提前结束,则标记胜利。
完整代码示例
import java.util.Random;
import java.util.Scanner;
public class PingTuGame {
private static Scanner scanner = new Scanner(System.in);
private static Random random = new Random();
// 记录空白格的行列坐标
private static int h = 0;
private static int l = 0;
private static int x = 0;
private static int y = 0;
public static void main(String[] args) {
int[][] gameGrid = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 0 }
};
initGrid(gameGrid);
System.out.println("游戏开始!请输入要移动的数字(1-8):\n");
playGame(gameGrid);
}
/**
* 游戏主循环
*/
public static void playGame(int[][] a) {
while (true) {
printfResult(a);
int inputVal = getUserInput();
locateCoord(inputVal, a);
if (isValidMove()) {
swapBlock(a);
if (checkVictory(a)) {
printfResult(a);
System.out.println("恭喜,游戏完成!");
break;
}
} else {
System.out.println("\n无法移动,请重新输入有效方向。\n");
}
}
}
/**
* 格式化打印当前棋盘
*/
public static void printfResult(int[][] a) {
for (int[] row : a) {
for (int val : row) {
System.out.print(val == 0 ? "[ ]" : String.format("[%d]", val));
}
System.out.println();
}
System.out.println();
}
/**
* 随机化初始局面(保证可解)
*/
public static void initGrid(int[][] a) {
// 初始默认右下角是0
h = 2; l = 2;
for (int i = 0; i < 100; i++) {
// 随机选取上下左右方向之一
int dir = random.nextInt(4);
int nx = h + getDirOffset(dir, true);
int ny = l + getDirOffset(dir, false);
if (isInBound(nx, ny)) {
swapOnce(nx, ny, a);
h = nx; l = ny;
}
}
}
private static int getDirOffset(int d, boolean isRow) {
switch(d) {
case 0: return isRow ? -1 : 0;
case 1: return isRow ? 1 : 0;
case 2: return 0; case 3: return isRow ? 0 : -1;
default: return 0;
}
}
private static boolean isInBound(int x, int y) {
return x >= 0 && x < 3 && y >= 0 && y < 3;
}
private static void swapOnce(int nx, int ny, int[][] a) {
int temp = a[h][l];
a[h][l] = a[nx][ny];
a[nx][ny] = temp;
}
/**
* 获取用户合法输入
*/
public static int getUserInput() {
System.out.print("输入目标数字: ");
String str = scanner.nextLine().trim();
try {
int num = Integer.parseInt(str);
if (num >= 1 && num <= 8) return num;
} catch (Exception e) {}
System.out.println("无效输入!\n");
return getUserInput();
}
/**
* 查找数字坐标存入全局x,y
*/
public static void locateCoord(int target, int[][] a) {
for (int i=0; i<a.length; i++) {
for (int j=0; j<a[i].length; j++) {
if (a[i][j] == target) { x=i; y=j; return; }
}
}
}
/**
* 判断是否符合移动规则
*/
public static boolean isValidMove() {
// 检查是否与空白格相邻
if ((Math.abs(h-x) == 1 && l == y) ||
(Math.abs(l-y) == 1 && h == x)) {
return true;
}
return false;
}
/**
* 执行实际交换并更新全局空白位置
*/
public static void swapBlock(int[][] a) {
int t = a[h][l];
a[h][l] = a[x][y];
a[x][y] = t;
h = x; l = y;
}
/**
* 检查是否达到目标排序
*/
public static boolean checkVictory(int[][] a) {
int c = 1;
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
if (i == 2 && j == 2) continue; // 跳过最后的0位
if (a[i][j] != c++) return false;
}
}
return true;
}
}
简要总结
本例通过二维数组与循环逻辑展示了Java控制台编程的基础形态。在实际生产环境中,通常会引入更复杂的类封装与事件驱动机制,但对于入门掌握数组寻址、对象状态流转和算法边界测试而言,该实现具有极高的参考价值。以上就是Java控制台实现3x3数字拼图游戏的详细内容,更多关于Java图形界面的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









