基于回溯算法破解任意关卡的一笔画玩微信小游戏

        去年一天,同桌让我帮他玩一个叫一笔画完的微信小游戏,我在那一关试了很久都没通过,突然有一个想法,我可以编码穷举出所有情况来尝试破解,于是去百度了一笔画完的相关问题,发现没有类似答案,于是便开始了两天的构思探索之旅。。。。。。

        首先,游戏界面由若干行和若干列的方格组成,其中有部分方格是空白的,有一个起始位置,行走的路线只能连续,不能重复,必须一笔连续不断的走玩所有方格才算成功,试探方法类似如度为三的完整树结构,以深度优先遍历树,寻找解答方案。

于是想到可以建模抽象解决这个问题:

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年,这些天突然想写博客,于是做个记录,百度发现有人在使用图像识别来确认方格位置和相关信息,并用安卓调试来实现全自动化辅助破解,于是也想尝试一下学学技术,接下来有机会更新

你可能感兴趣的:(game)