第二章 趣味迷宫

来源:互联网 发布:利用网络漏洞赚钱 编辑:程序博客网 时间:2024/05/16 00:48



这一章来谈一谈迷宫的走法,以及做一个简单的迷宫游戏,可以自己DIY迷宫地图
我们将迷宫问题难度上升一点,就是找一条最近的路径走出迷宫
一般针对最短路径问题,bfs是最简单的选择,A*是较好的选择,但是A*过程较繁琐,今天我们将采用IDA*算法来实现这个寻找迷宫出口问题
算法思想和流程:
IDA*算法简单的讲就是迭代+A*的实现,因实现过程非常简单,而且效率还很优,所以掌握IDA*势在必行
1、没有学习IDA*算法以前,觉得如果是最短路径问题,则dfs是无法实现的,bfs可以实现,但是IDA*告诉了我dfs怎么实现最短路径问题,而且实现的更好
2、、回顾下IDA*的步骤,没有了A*的优先队列,甚至连bfs广搜所需的简单队列和判重数组都不用,从一个阈值开始递归,这个值一般可以理解为递归的最大深度,若找不到目标点,则这个值进行扩大,列入++操作,再重新递归操作,找到则返回,返回的一定是最优值
3、回顾下IDA*的判断函数(IDA*的精髓啊):当前局面的估价函数值+当前的搜索深度 > 预定义的最大搜索深度时,就进行剪枝。
实现起来较容易,代码量也很少
//最近的路走出迷宫//IDA*算法实现#include <iostream>using namespace std;#define M 15//行#define N 20//列int map[][N]={{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},{1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1},{1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,0,1},{1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,1,0,1},{1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1},{1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,1},{1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1},{1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1},{1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1},{1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1},{1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1},{1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1},{1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1},{1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0}};int dir[][2]={-1,0,0,-1,1,0,0,1};int starti=0,startj=0;//开始点坐标int endi=M-1,endj=N-1;//结束点坐标int maxDeep;//最大深度int H(int i,int j){//估价函数return abs(endi-i)+abs(endj-j);}bool dfs(int curi,int curj,int depth){if(depth+H(curi,curj)>maxDeep)//IDA*估价剪枝return false;if(curi==endi&&curj==endj)return true;for(int i=0;i<4;i++){int ni=curi+dir[i][0];int nj=curj+dir[i][1];if(ni>=0&&ni<M&&nj>=0&&nj<N&&map[ni][nj]==0){map[ni][nj]=2;if(dfs(ni,nj,depth+1))return true;map[ni][nj]=0;}}return false;}int IDAstar(){maxDeep=H(starti,startj);map[starti][startj]=2;while(!dfs(starti,startj,0))maxDeep++;return maxDeep;}int main(){    cout<<IDAstar();    return 0;}

下面我们的主要任务就是做一个这样的游戏了,可以模拟动态的走出这个迷宫,还可以自己DIY通路和障碍,动手开始吧
HTML代码如下,只要复制粘贴,保存html打开就能见到后面的效果了
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>    <title></title><style type="text/css">body,div,h2,ul,li{margin:0;padding:0;}body{font:12px/1.5 Arail;}.box{width:860px;margin:10px auto;background:#eee;border:1px solid #b8b8b8;overflow:hidden}.title{height:30px;line-height:30px;font-size:14px;padding:0 15px 0 35px;border-bottom:1px solid #b8b8b8;background:#fafafa url(http://js.alixixi.com/img/mm/ico.gif) 5px 50% no-repeat;}.title span{float:left;}.title a{float:right;color:#06f;outline:none;}.title a:hover{color:red;}    .box .tool {        width:300px;        float:left;    }    .box .content {        width:480px;        margin-left:310px;    }    .tool div {        margin:10px auto;        height:40px;        text-align:center;    }    .content .tag {        height:30px;        line-height:30px;    }    .content td {        width:10px;        height:10px;        font-size:xx-large;        line-height:10px;        border:1px solid #c3c3c3;        background:#fff;        text-align:center;    }</style><script type="text/javascript">    //一些常量        var matrix = [[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],[1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],[1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1],[1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1],[1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1],[1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1],[1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],[1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1],[1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],[1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1],[1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],[1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1],[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]    ];    var M = 15, N = 20;    var dir = [[-1, 0], [0, -1], [1, 0], [0, 1]];    var starti = 0, startj = 0;//开始点坐标    var endi = M - 1, endj = N - 1;//结束点坐标    function H(i,j){//估价函数        return Math.abs(endi - i) + Math.abs(endj - j);    }    var BLACK="#000";    var BLUE="#06f";    var WHITE="#fff";</script><script type="text/javascript">    //一些公共函数    //获取ID    var $ = function (id) { return typeof id === "string" ? document.getElementById(id) : id };    //获取tagName    var $$ = function (tagName, oParent) { return (oParent || document).getElementsByTagName(tagName) };    //获取class    var $$$ = function (sClass, oParent) {        var aClass = [],        i = 0,        reClass = new RegExp("(\\s|^)" + sClass + "($|\\s)"),        aElement = $$("*", oParent);        for (i = 0; i < aElement.length; i++) reClass.test(aElement[i].className) && aClass.push(aElement[i]);        return aClass    };</script><script type="text/javascript">    //创建数独对象    var Maze = function () { this.initialize.apply(this, arguments) };    Maze.prototype = {        initMatrix: function (matrix,Map) {            for (var i = 0; i < M; i++) {                matrix[i] = new Array(N);                for (var j = 0; j < N; j++) {                    matrix[i][j] = Map[i][j];                }            }        },        renewMatrix: function (matrix,Map) {            for (var i = 0; i < M; i++) {                for (var j = 0; j < N; j++) {                    matrix[i][j] = Map[i][j];                }            }        },        initialize: function (obj ,Map) {            var oThis = this;            this.Parent = $(obj);//获得table对象            this.Table = $$("table", this.Parent)[0];            this.tag = $$$("tag", this.Parent)[0];            this.ButtonA = $$$("answer", this.Parent)[0];            this.ButtonB = $$$("restore", this.Parent)[0];            this.ButtonC = $$$("show", this.Parent)[0];            this.ButtonD = $$$("diy", this.Parent)[0];            this.matrix = new Array(M);//存放数独矩阵            this.diyMatrix = new Array(M);//diy迷宫            this.Td = [];//table中的所有td列矩阵            this.maxDeep = 0;            this.stime = null;//计时            this.initMatrix(this.matrix, Map);            this.initMatrix(this.diyMatrix, Map);            this.dom = document.documentElement || document.body;            this.ButtonA.onclick = function () {                oThis.tag.innerText = "运行";                oThis.initOperation();                oThis.show();                oThis.answer();                oThis.print();            }            this.ButtonB.onclick = function () {                oThis.tag.innerText = "还原迷宫";                oThis.initOperation();                oThis.show();            }            this.ButtonC.onclick = function () {                oThis.tag.innerText = "显示答案";                oThis.initOperation();                oThis.answer();                oThis.show();            }            this.ButtonD.onclick = function () {                oThis.tag.innerText = "DIY迷宫";                oThis.initOperation();                oThis.show();                oThis.diy();            }            this.create(Map);        },        initOperation: function () {//初始化操作            var oThis = this;            oThis.renewMatrix(oThis.matrix, oThis.diyMatrix);            clearInterval(oThis.stime);        },        create: function (Map) {            var oThis = this;            var aFrag = document.createDocumentFragment();            var i = 0, j = 0;            for (i = 0; i < M; i++) {                var tr = document.createElement("tr");                oThis.Td.push([]);                for (j = 0; j < N; j++) {                    var td = document.createElement("td");                    if (Map[i][j] == 1) td.style.backgroundColor = BLACK;                    oThis.Td[i].push(td);                                        tr.appendChild(td);                }                aFrag.appendChild(tr);            }            this.Table.appendChild(aFrag);        },        print: function () {            var oThis = this;            var curi = starti, curj = startj;            var preDir = -3;//访问的上一个方向                        this.stime = setInterval(function () {                oThis.Td[curi][curj].style.backgroundColor = BLUE;                if (curi == endi && curj == endj) clearTimeout(oThis.stime);                for (var i = 0; i < 4; i++) {                    var ni = curi + dir[i][0];                    var nj = curj + dir[i][1];                    if (ni >= 0 && ni < M && nj >= 0 && nj < N && Math.abs(i - preDir) != 2 && oThis.matrix[ni][nj] == 2) {                        curi = ni, curj = nj;                        preDir = i;                        break;                    }                }            }, 100);        },        show: function () {            for (var i = 0; i < M; i++)                for (var j = 0; j < N; j++) {                    if (this.matrix[i][j] == 2)                        this.Td[i][j].style.backgroundColor = BLUE;                    else if (this.matrix[i][j] == 1)                        this.Td[i][j].style.backgroundColor = BLACK;                    else this.Td[i][j].style.backgroundColor = WHITE;                }        },        find:function(obj){            for (var i = 0; i < M; i++)                for (var j = 0; j < N; j++)                    if (this.Td[i][j] == obj)                        return { i: i, j: j };        },        diy: function () {            var oThis=this;            for (var i = 0; i < M; i++) {                for (var j = 0; j < N; j++) {                    this.Td[i][j].onclick = function () {                        var pos = oThis.find(this);                        var i=pos.i,j=pos.j;                        if (oThis.diyMatrix[i][j] == 0) {                            oThis.diyMatrix[i][j] = 1;                            this.style.backgroundColor = BLACK;                        } else {                            oThis.diyMatrix[i][j] = 0;                            this.style.backgroundColor = WHITE;                        }                    }                }            }        },        answer: function () {            this.IDAstar();            //this.show();        },        dfs:function(curi, curj, depth) {                    if (depth + H(curi, curj) > this.maxDeep)//IDA*估价剪枝                return false;            if (curi == endi && curj == endj)                return true;            for (var i = 0; i < 4; i++) {                var ni = curi + dir[i][0];                var nj = curj + dir[i][1];                if (ni >= 0 && ni < M && nj >= 0 && nj < N && this.matrix[ni][nj] == 0) {                    this.matrix[ni][nj] = 2;                    if (this.dfs(ni, nj, depth + 1) == true) return true;                    this.matrix[ni][nj] = 0;                }            }            return false;        },        IDAstar:function(){            this.maxDeep = H(starti, startj);            this.matrix[starti][startj]=2;            while (this.dfs(starti, startj, 0) == false) {                if (this.maxDeep > 100) break;                this.maxDeep = this.maxDeep + 1;            }        }    };    window.onload = function () {        var Box = $$$("box");        //创建实例        new Maze(Box[0], matrix);    };</script></head><body><div class="box">    <h2 class="title"><span>迷宫模拟</span></h2>    <div class="tool">        <div><button class="answer">运行</button></div>        <div><button class="restore">还原迷宫</button></div>        <div><button class="show">显示答案</button></div>        <div><button class="diy">DIY迷宫</button></div>    </div>    <div class="content">        <div class="tag">默认迷宫</div>        <table class="sudoku">                    </table>    </div></div></body></html>



效果如下:
初始状态:

点击运行:
蓝色条会一直动
点击显示答案会将最近的路径显示出来
点击DIY迷宫可以自己DIY,然后再点击运行或者显示答案,会重新计算结果


后记:
我一直觉得编程没有那么枯燥,也可以是玩出来的



王川
2014/2/13
0 0
原创粉丝点击