去年一天,同桌让我帮他玩一个叫一笔画完的微信小游戏,我在那一关试了很久都没通过,突然有一个想法,我可以编码穷举出所有情况来尝试破解,于是去百度了一笔画完的相关问题,发现没有类似答案,于是便开始了两天的构思探索之旅。。。。。。
首先,游戏界面由若干行和若干列的方格组成,其中有部分方格是空白的,有一个起始位置,行走的路线只能连续,不能重复,必须一笔连续不断的走玩所有方格才算成功,试探方法类似如度为三的完整树结构,以深度优先遍历树,寻找解答方案。
于是想到可以建模抽象解决这个问题:
1,游戏中的方格整体对应一个二维数组,单个方格对应数组中的一个元素,数组的行数和列数与二维数组的行数和列数对应
2,每个方格分别有true和false两种属性,初始化可以走的方格为true,不能走的和已经走过的为false
3,当所有初始化为true方格被走过变为false时,破解结束
下面看关键的方法片段:
int nb = 0;
ArrayList nbList = new ArrayList();
ArrayList xList = new ArrayList();
ArrayList yList = new ArrayList();
//初始化步数,初始化记录每一步上下左右行走方向的数组,和每一步对应的 x,y的坐标点
void isCan(boolean[][] isBooleanlist, int lenth, int x, int y, int row, int column) {
//判断旁边的四个点是否符合要求 参数为空白点个数,每一步的横纵坐标,以及边界大小
if (x + 1 < row && isBooleanlist[x + 1][y] == true) {
nbList.add(1);//1对应向右试探
nb++;
isBooleanlist[x + 1][y] = false;//试探过的方格就不能再试了
xList.add(x + 2);
yList.add(y + 1);//记录这一步的位置
System.out.println("初始位置是: " + (x + 1) + "," + (y + 1));
System.out.println("第:" + nb + "步的位置是: " + (x + 2) + "," + (y + 1));
System.out.println(" ");
isCan(isBooleanlist, lenth, x + 1, y, row, column);
//回调方法本身 进行下一步试探
}
其中回调方法本身和记录试探的方向和坐标是该算法的核心精髓
当回调的方法判断为true,即还可以继续试探,直到试探到判断为false时,就需要返回上一步接着遍历其他情况,如此循环,直到解决问题,下面来看返回上一级试探的相关代码
if (row * column - 1 == nb) {
System.out.println("成功");
}
if (row * column - lenth - 1 != nb) {
if (nb - 1 >= 0 && nbList.get(nb - 1) == 1) {
isBooleanlist[x][y] = true;
x = x - 1;
//nbList中对应的1,2,3,4,分别对应的是下一步试探的方向
}
if (nb - 1 >= 0 && nbList.get(nb - 1) == 2) {
isBooleanlist[x][y] = true;
x = x + 1;
}
if (nb - 1 >= 0 && nbList.get(nb - 1) == 3) {
isBooleanlist[x][y] = true;
y = y - 1;
}
if (nb - 1 > 00 && nbList.get(nb - 1) == 4) {
isBooleanlist[x][y] = true;
y = y + 1;
}
if (nb - 1 == 0) {
System.out.println("此情况无解,可能是输入的参数有误!");
}
nbList.remove(nb - 1);
xList.remove(nb - 1);
yList.remove(nb - 1);
nb--;
//回退到上一步
}
如何回退是该方法的关键,其中逻辑部分也很重要,下面来看完整代码
package Game;
import java.util.ArrayList;
import java.util.Scanner;
public class GameCrack {
static boolean[][] isFeasible(int row, int column) {
//初始化可以使用的小块为 true
boolean[][] isBooleanlist;
isBooleanlist = new boolean[row][column];
for (int i = 0; i < row; i++)
for (int j = 0; j < column; j++) {
isBooleanlist[i][j] = true;
}
return isBooleanlist;
}
static boolean[][] addblank(boolean[][] isBooleanlist, int x, int y) {
//添加空白小块为 false,已经使用的小块也为 false
isBooleanlist[x][y] = false;
return isBooleanlist;
}
static int inputinit() {
Scanner scan = new Scanner(System.in);
//输入初始化的方格大小
int nexint;
while (true) {
int choice = scan.nextInt();
if (0 < choice) {
nexint = choice;
break;
} else {
System.out.println("输入非法 可能超过了合理范围 请重新输入");
continue;
}
}
return nexint;
}
static int inputblank(int number) {
//输入空白处的坐标,同理可输入初始位置, 有大小限制
Scanner scan = new Scanner(System.in);
int nexint;
while (true) {
int choice = scan.nextInt();
if (0 < choice && choice <= number) {
nexint = choice;
break;
} else {
System.out.println("输入非法 可能超过了合理范围 请重新输入");
continue;
}
}
return nexint;
}
int nb = 0;
ArrayList nbList = new ArrayList();
ArrayList xList = new ArrayList();
ArrayList yList = new ArrayList();
//初始化步数 和每一步对应的 x,y的坐标点
void isCan(boolean[][] isBooleanlist, int lenth, int x, int y, int row, int column) {
//判断旁边的四个点是否符合要求
//回调 连续判断
if (x + 1 < row && isBooleanlist[x + 1][y] == true) {
nbList.add(1);
nb++;
isBooleanlist[x + 1][y] = false;
xList.add(x + 2);
yList.add(y + 1);
System.out.println("初始位置是: " + (x + 1) + "," + (y + 1));
System.out.println("第:" + nb + "步的位置是: " + (x + 2) + "," + (y + 1));
System.out.println(" ");
isCan(isBooleanlist, lenth, x + 1, y, row, column);
}
if (x - 1 >= 0 && isBooleanlist[x - 1][y] == true) {
nbList.add(2);
nb++;
isBooleanlist[x - 1][y] = false;
xList.add(x);
yList.add(y + 1);
System.out.println("初始位置是: " + (x + 1) + "," + (y + 1));
System.out.println("第:" + nb + "步的位置是: " + (x) + "," + (y + 1));
System.out.println(" ");
isCan(isBooleanlist, lenth, x - 1, y, row, column);
}
if (y + 1 < column && isBooleanlist[x][y + 1] == true) {
nbList.add(3);
nb++;
isBooleanlist[x][y + 1] = false;
xList.add(x + 1);
yList.add(y + 2);
System.out.println("初始位置是: " + (x + 1) + "," + (y + 1));
System.out.println("第:" + nb + "步的位置是: " + (x + 1) + "," + (y + 2));
System.out.println(" ");
isCan(isBooleanlist, lenth, x, y + 1, row, column);
}
if (y - 1 >= 0 && isBooleanlist[x][y - 1] == true) {
nbList.add(4);
nb++;
isBooleanlist[x][y - 1] = false;
xList.add(x + 1);
yList.add(y);
System.out.println("初始位置是: " + (x + 1) + "," + (y + 1));
System.out.println("第:" + nb + "步的位置是: " + (x + 1) + "," + (y));
System.out.println(" ");
isCan(isBooleanlist, lenth, x, y - 1, row, column);
}
if (row * column - 1 == nb) {
System.out.println("成功");
}
if (row * column - lenth - 1 != nb) {
if (nb - 1 >= 0 && nbList.get(nb - 1) == 1) {
isBooleanlist[x][y] = true;
x = x - 1;
}
if (nb - 1 >= 0 && nbList.get(nb - 1) == 2) {
isBooleanlist[x][y] = true;
x = x + 1;
}
if (nb - 1 >= 0 && nbList.get(nb - 1) == 3) {
isBooleanlist[x][y] = true;
y = y - 1;
}
if (nb - 1 > 00 && nbList.get(nb - 1) == 4) {
isBooleanlist[x][y] = true;
y = y + 1;
}
if (nb - 1 == 0) {
System.out.println("此情况无解,可能是输入的参数有误!");
}
nbList.remove(nb - 1);
xList.remove(nb - 1);
yList.remove(nb - 1);
nb--;
//isBooleanlist[x][y] = true;
}
if (row * column - lenth - 1 == nb) {
for (int i = 0; i < row * column - lenth - 1; i++)
{
System.out.println("第" + (i + 1) + "步的位置是: " + (xList.get(i)) + "," + (yList.get(i)));
}
}
}
public static void main(String[] args) {
GameCrack gameCrack = new GameCrack();
System.out.println("请输入横坐标");
int row = inputinit();
System.out.println("请输入纵坐标");
int column = inputinit();
boolean[][] isBooleanlist = isFeasible(row, column);
System.out.println("请输入开头位置横坐标");
int x = inputblank(row) - 1;
System.out.println("请输入开头位置纵坐标");
int y = inputblank(column) - 1;
addblank(isBooleanlist, x, y);
System.out.println("请输入空白点的个数");
int lenth = inputinit();
for (int i = 0; i < lenth; i++) {
System.out.println("请输入第" + (i + 1) + "个空白点的横坐标");
int m = inputblank(row) - 1;
System.out.println("请输入第" + (i + 1) + "个空白点的纵坐标");
int n = inputblank(column) - 1;
addblank(isBooleanlist, m, n);
}
gameCrack.isCan(isBooleanlist, lenth, x, y, row, column);
}
}
代码写于2018年,这些天突然想写博客,于是做个记录,百度发现有人在使用图像识别来确认方格位置和相关信息,并用安卓调试来实现全自动化辅助破解,于是也想尝试一下学学技术,接下来有机会更新