调试 15 拼图中的无效移动

Debugging invalid moves in a 15 puzzle

我做了一点15 puzzle,我想在开始时对其进行洗牌。我从完成的状态开始,随机 "fakeClicks" 对根据我的代码有些有效但大部分无效的图块进行随机操作。有效的 "fakeClicks" 导致 emptyTileselectedTile 通过交换它们的 topleft 值来交换它们的位置。

一切(除了尚不存在的 checkCompleteness() 方法)似乎都有效 - 直到有人真正尝试解决难题。使用较小的 n,我达到 unsolvable game situation 的概率超过 50%。

在洗牌过程中我只做有效的移动,这怎么可能?显然这一定是关于我的代码检查移动是否有效:

if ((Math.abs(selectedX - emptyX) === tileSize) ^ (Math.abs(selectedY - emptyY) === tileSize)) {

(^(异或)是为了防止对角线移动。)

有人知道问题出在哪里吗?或者有人对好的调试策略有什么建议吗?调试了一个多小时,有点懵

var idList = ["t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t0"];
var tileSize = 100;

var init = function() {
    // place tiles on the board and add listener
    for (var column = 0; column < 4; column++) {
        for (var row = 0; row < 4; row++) {
            var div = document.querySelector("." + idList[row * 4 + column]);
            div.style.top = row * tileSize + "px";
            div.style.left = column * tileSize + "px";
            if (idList[row * 4 + column] !== "t0") {
                div.addEventListener("click", clickListener);
            }
        }
    }
    // shuffle tiles
    for (i = 0; i < 1000; i++) {
        var fakeClick = parseInt(Math.random() * 15);
        swapTiles(idList[fakeClick]);
    }
};

var clickListener = function(e) {
    var selectedTileClass = e.target.classList[1];
    swapTiles(selectedTileClass);
    //checkCompleteness(); // to be done later
};

var swapTiles = function(selectedTileClass) {
    // get empty tile and selected tile
    var selectedTile = document.querySelector("." + selectedTileClass);
    var selectedX = parseInt(selectedTile.style.left);
    var selectedY = parseInt(selectedTile.style.top);
    var emptyTile = document.querySelector(".t0");
    var emptyX = parseInt(emptyTile.style.left);
    var emptyY = parseInt(emptyTile.style.top);
    // only swap tiles  if selected tile "next to" empty tile
    if ((Math.abs(selectedX - emptyX) === tileSize) ^ (Math.abs(selectedY - emptyY) === tileSize)) {
        selectedTile.style.left = emptyX + "px";
        selectedTile.style.top = emptyY + "px";
        emptyTile.style.left = selectedX + "px";
        emptyTile.style.top = selectedY + "px";
    }
};
.board {
    position: relative;
    width: 400px;
    height: 400px;
    margin: auto;
    background-color: firebrick;
    border: 2px firebrick solid;
}

.tile {
    position: absolute;
    width: 100px;
    height: 100px;
    border: 2px firebrick solid;
    box-sizing: border-box;
    background-color: orange;
    line-height: 100px;
    font-size: 2rem;
    font-weight: bold;
    font-family: Arial, sans-serif;
    color: firebrick;
    text-align: center;
    transition: all .25s linear;
    cursor: pointer;
}

.t0 {
    position: absolute;
    width: 96px;
    height: 96px;
    margin: 2px;
    border: 2px orange solid;
    box-sizing: border-box;
    pointer-events: none;
    transition: all .25s linear;
}
<html>
<meta charset="utf-8">

<head>
    <script type="text/javascript" src="js.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body onload="init();">
    <div class="wrapper">
        <div class="center">
            <div class="board">
                <div class="tile t1">1</div>
                <div class="tile t2">2</div>
                <div class="tile t3">3</div>
                <div class="tile t4">4</div>
                <div class="tile t5">5</div>
                <div class="tile t6">6</div>
                <div class="tile t7">7</div>
                <div class="tile t8">8</div>
                <div class="tile t9">9</div>
                <div class="tile t10">10</div>
                <div class="tile t11">11</div>
                <div class="tile t12">12</div>
                <div class="tile t13">13</div>
                <div class="tile t14">14</div>
                <div class="tile t15">15</div>
                <div class="t0"></div>
            </div>
        </div>
    </div>
</body>

</html>

你是对的,你的测试是错误的。

想象一个小板,中间是所选的图块

ooooo
ooooo
ooxoo
ooooo
ooooo

现在看看 2 个谓词的两个真值表根据空块的位置给出什么。

ftftf
ftftf
ftxtf
ftftf
ftftf

fffff
ttttt
ffxff
ttttt
fffff

将它们与异或运算混合,你会得到

ftftf
tftft
ftxtf
tftft
ftftf

这意味着您在方块周围的 "first circle" 上得到了正确的响应,但是在离方块较远的地方得到了错误的响应。