游戏里的小人如何走路?百行HTML5+JS能搜索出路径吗?

 用了HTML5里的canvas. 这个"游戏"的”玩法“是:

  1. 改迷宫折腾电脑
  2. 改程序折腾自己:-)。我自以为程序挺简明,注释挺多,比如:
    • // 全局变量坑死人,这里曾经少个var 
    • // 虽然直接drawImage有时能出来,但这么做绝对必要。坑了我好长时间。

单.HTML文件146行,包括数张嵌入式.gif图片和JS。下面是全部JS(112行):

复制代码
ctx = gmaze.getContext('2d')

function reset_maze(){
    X = Xin.value; if(X > 32 || X < 6) X = 20
    Y = Yin.value; if(Y > 20 || Y < 6) Y = 13
    Xin.value = X; Yin.value = Y
    maze = new Array(); for(y = 0; y < Y; y++){
        var    row = new Array() // new Array(3)不是创建长度为3的数组
        for(x = 0; x < X; x++) row.push(Math.random() < 0.7 ? ' ' : 'w')
        maze.push(row)
    }
    maze[cx = 0][cy = 0] = 'r'    // cx,cy记录当前机器人位置
    gmaze.width = X * 32; gmaze.height = Y * 32; draw_maze()
}; reset_maze()

function clear_path() {
    for(y = 0; y < Y; y++) for(x = 0; x < X; x++){
        var    c = maze[y][x]
        if(c == 'x' || c == 'p' || c == 'r') maze[y][x] = ' '
    }
    stepcnt = 0
}

function draw_maze(){
    for(y = 0; y < Y; y++) for(x = 0; x < X; x++){
        var    c = maze[y][x]
        if(c == 'r') draw_img(img_robot, x, y)
        else if(c == 'w') draw_img(img_wall, x, y)
        else if(c == 'p') draw_img(img_flag, x, y)
        else if(c == ' ') draw_blk('#fff', x, y)
        else draw_blk('#f00', x, y)
    }
}

// 虽然直接drawImage有时能出来,但这么做绝对必要。坑了我好长时间。
function draw_img(img, x, y){
    var i = new Image(); i.src = img.src
    i.onload = function(){ ctx.drawImage(i, x * 32, y * 32) }
}

function draw_blk(color, x, y){    ctx.fillStyle = color; ctx.fillRect(x * 32, y * 32, 32, 32) }

// mx, my记录鼠标指针位置
d = document; d.addEventListener('mousemove', function(e){ mx = e.x; my = e.y })

// 像素坐标到块坐标转换。border+wall=8+32. round() is bad, round() is wrong.
function get_x() { // 
    var x = Math.floor((mx - 40) / 32)
    if(x < 0 || x >= X) throw 'X超出范围。'
    return x
}
function get_y() {
    var y = Math.floor((my - 40) / 32)
    if(y < 0 || y >= Y) throw 'Y超出范围。'
    return y
}

d.addEventListener('mousedown', function(e){ // 可以忽略exception
    if(e.which != 1) return; // Not left button
    var    x = get_x(), y = get_y()
    var    c = maze[y][x]
    if(c == 'w') maze[y][x] = ' ', draw_blk('#fff', x, y)
    else if (c == ' ') maze[y][x] = 'w', draw_img(img_wall, x, y)
})

d.addEventListener('keydown', function(e){
    if (e.keyCode != 71) return    // Not 'g'
    try{
        tx = get_x(), ty = get_y()    // target x, y, 全局变量
        clear_path()
        //alert('Searching for ' + cx + ',' + cy + ' to ' + tx + ',' + ty)
        ok = search(cx, cy) 
        if(ok) maze[cy = ty][cx = tx] = 'r'
        else {
            maze[cy][cx] = 'r'
            alert('Please try a nearer target.')
        }
        draw_maze()
    }
    catch(e){}
})

function search(x, y){
    if(x == tx && y == ty) return true
    if(++stepcnt > 1000000) return false
    if(x<0 || x>=X || y<0 || y>=Y) {
        console.log(x, y)
        return false
    }
    if(maze[y][x] != ' ') {
        console.log(x, y, maze[y][x])
        return false
    }
    maze[y][x] = 'p'
    var    dxdy = [[0,-1],[0,1],[-1,0],[1,0]]
    var    e_i = [1,2,3,4] // evaluation_index
    var    i, j
    for(i = 0; i < 4; i++) {
        var    a = x + dxdy[i][1], b = y + dxdy[i][0]
        var    c = tx - a, d = ty - b
        var    t = c * c + d * d    // 距离的平方
        e_i[i] = (t << 2) | i
    }
    // 默认情况下,sort方法按字母顺序对元素排序。https://www.codenong.com/1063007/
    e_i.sort((a, b) => a - b)
    for(j = 0; j < 4; j++) {
        i = e_i[j] & 0x3    // 全局变量坑死人,这里曾经少个var
        if(search(x + dxdy[i][1], y + dxdy[i][0])) return true
    }
    maze[y][x] = 'x'; return false
}
// 写完了才知道let和const是JavaScript里相对较新的变量声明方式。let在很多方面与var相似。
复制代码

点这里下载HTML+JS。下面是HTML的不包含嵌入图片的部分:

复制代码
<html><meta charset="gbk"><title>走迷宫</title><style>
/* https://www.w3school.com.cn/cssref/css_selectors.asp */
* { font:12pt 'Segoe UI' }
#wall { position:absolute; left:8px; top:8px; padding:32px;
background-image:url(data:image/gif;base64,...);
}
#gmaze { cursor:hand }
#panel { float:right; top:32px }
    h6 { font:bold 14pt 'Segoe UI'; color:green; margin:1em }
    input { width:2em }
pre { display:none }
</style>
<body>
<div id="wall"><canvas id="gmaze"/></div>
<div id="panel">
    <h6>你设计一个迷宫,机器人来走</h6>
    <p style="text-align:center">
        <button onclick="reset_maze()">重新生成</button>
        <input type="text" id="Xin" value="20"/> X 
        <input type="text" id="Yin" value="17"/>的迷宫
    </p>
    <ul>
    <li>编辑: 在迷宫里按鼠标左键切换路或墙。<br>最外面的墙不能改变。</li>
    <li>按 g 键后,机器人会试图走到鼠标指针所在处。</li>
    <li style='font-size:10pt'>打开开发人员工具后,键盘焦点可能不在页面内。<br>此时可点击页面内任意文本框把焦点切回来。<br>鼠标双击容易误操作。</li>
    </ul>
</div>
复制代码

 想起扫地机器人的笑话: 把droppings摊了薄薄一层; 展屎官的迷思……

posted @   Fun_with_Words  阅读(110)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?









 和4张牌。

点击右上角即可分享
微信分享提示