滑动拼图检查功能javascript

Checking function for sliding puzzle javascript

我创建了一个具有不同格式的滑动拼图,例如:3x3、3x4、4x3 和 4x4。当您 运行 我的代码时,您可以在右侧看到一个 selection 框,您可以在其中选择 4 种格式。滑动拼图快完成了。 但是我需要一个函数来检查每一步是否解开了谜题,如果是的话,它应该给出像 "Congrantulations you solved it!" 或 "You won!" 这样的一行。知道如何让它发挥作用吗?

在javascript代码中你可以看到第一个函数loadFunc()是将每块替换为空白,后面的函数是select一种格式,将格式改为它。 Shiftpuzzlepieces 函数使您可以将每个拼图移动到空白 space 中。函数洗牌随机化每个棋子的位置。如果您有任何问题或理解问题,请随时在评论中提问。非常感谢。

由于我没有足够的声誉,我将 post 一个 link 到这里的图像:http://imgur.com/a/2nMlt。这些图片现在只是占位符。

Here is the jsfiddle:

    http://jsfiddle.net/Cuttingtheaces/vkyxgwo6/19/
    $(document).on('click','.puzzlepiece', function(){
        var count = 0;
         var imgarray = []; 
        var test =[0,1,2,3,4,5,6,7,8,'blank']
        $('#slidingpuzzleContainer img').each(function(i){
          var imgalt =  $(this).attr('alt');             
            imgarray[i] = imgalt;            
            count++;

        });
        var is_same = (imgarray.length == test.length) &&   imgarray.every(function(element, index) {
        return element === array2[index]; 
    });

        console.log(is_same);    ///it will true if two array is same           
    });

试试这个...这仅适用于 3*3.. 您传递参数并使数组值动态..

一如既往,有一种 "hacky" 简单的方法可以做到这一点,还有一种更优雅但需要对代码进行重大更改的方法。

骇人听闻的方式

为了尽可能快速和肮脏地完成这项工作,我会解析 id-s 个片段来检查它们的顺序是否正确,因为它们有这个方便的模式 "position" + it's expected index or "blank"

function isFinished() {
    var puzzleEl = document.getElementById('slidingpuzzleContainer').children[0];
    // convert a live list of child elements into regular array
    var pieces = [].slice.call(puzzleEl.children);

    return pieces
        .map(function (piece) {
            return piece.id.substr(8); // strip "position" prefix
        })
        .every(function (id, index, arr) {
            if (arr.length - 1 == index) {
                // last peace, check if it's blank
                return id == "blank";
            }
            // check that every piece has an index that matches its expected position
            return index == parseInt(id);
        });
}

现在我们需要在某个地方检查它,自然最好的地方是在每次移动之后,所以 shiftPuzzlepieces() 应该更新为调用 isFinished() 函数,如果它 returns true:

function shiftPuzzlepieces(el) {
    // ...
    if (isFinished()) {
        alert("You won!");
    }
}

瞧瞧:live version

我将如何实现这个游戏

对我来说,实现这个的正确方法是跟踪一些数据结构中片段的当前位置并以类似的方式检查它,但不遍历 DOM 或检查节点的 id-s。此外,它将允许实现类似 React.js 应用程序的东西:onclick 处理程序会改变当前游戏的状态,然后将其渲染到 DOM.

我将如何实现游戏:

/**
 * Provides an initial state of the game
 * with default size 4x4
 */
function initialState() {
  return {
    x: 4,
    y: 4,
    started: false,
    finished: false
  };
}

/**
 * Inits a game
 */
function initGame() {
  var gameContainer = document.querySelector("#slidingpuzzleContainer");
  var gameState = initialState();

  initFormatControl(gameContainer, gameState);
  initGameControls(gameContainer, gameState);

  // kick-off rendering
  render(gameContainer, gameState);
}

/**
 * Handles clicks on the container element
 */
function initGameControls(gameContainer, gameState) {
  gameContainer.addEventListener("click", function hanldeClick(event) {
    if (!gameState.started || gameState.finished) {
      // game didn't started yet or already finished, ignore clicks
      return;
    }
    if (event.target.className.indexOf("piece") == -1) {
      // click somewhere not on the piece (like, margins between them)
      return;
    }

    // try to move piece somewhere
    movePiece(gameState, parseInt(event.target.dataset.index));

    // check if we're done here
    checkFinish(gameState);

    // render the state of game
    render(gameContainer, gameState);

    event.stopPropagation();
    return false;
  });
}

/**
 * Checks whether game is finished
 */
function checkFinish(gameState) {
  gameState.finished = gameState.pieces.every(function(id, index, arr) {
    if (arr.length - 1 == index) {
      // last peace, check if it's blank
      return id == "blank";
    }
    // check that every piece has an index that matches its expected position
    return index == id;
  });
}

/**
 * Moves target piece around if there's blank somewhere near it
 */
function movePiece(gameState, targetIndex) {
  if (isBlank(targetIndex)) {
    // ignore clicks on the "blank" piece
    return;
  }

  var blankPiece = findBlankAround();
  if (blankPiece == null) {
    // nowhere to go :(
    return;
  }

  swap(targetIndex, blankPiece);


  function findBlankAround() {
    var up = targetIndex - gameState.x;
    if (targetIndex >= gameState.x && isBlank(up)) {
      return up;
    }
    var down = targetIndex + gameState.x;
    if (targetIndex < ((gameState.y - 1) * gameState.x) && isBlank(down)) {
      return down;
    }
    var left = targetIndex - 1;
    if ((targetIndex % gameState.x) > 0 && isBlank(left)) {
      return left;
    }
    var right = targetIndex + 1;
    if ((targetIndex % gameState.x) < (gameState.x - 1) && isBlank(right)) {
      return right;
    }
  }

  function isBlank(index) {
    return gameState.pieces[index] == "blank";
  }

  function swap(i1, i2) {
    var t = gameState.pieces[i1];
    gameState.pieces[i1] = gameState.pieces[i2];
    gameState.pieces[i2] = t;
  }
}

/**
 * Handles form for selecting and starting the game
 */
function initFormatControl(gameContainer, state) {
  var formatContainer = document.querySelector("#formatContainer");
  var formatSelect = formatContainer.querySelector("select");
  var formatApply = formatContainer.querySelector("button");

  formatSelect.addEventListener("change", function(event) {
    formatApply.disabled = false;
  });

  formatContainer.addEventListener("submit", function(event) {
    var rawValue = event.target.format.value;
    var value = rawValue.split("x");

    // update state
    state.x = parseInt(value[0], 10);
    state.y = parseInt(value[1], 10);
    state.started = true;
    state.pieces = generatePuzzle(state.x * state.y);

    // render game
    render(gameContainer, state);

    event.preventDefault();
    return false;
  });
}

/**
 * Renders game's state into container element
 */
function render(container, state) {
  var numberOfPieces = state.x * state.y;
  updateClass(container, state.x, state.y);
  clear(container);

  var containerHTML = "";
  if (!state.started) {
    for (var i = 0; i < numberOfPieces; i++) {
      containerHTML += renderPiece("", i) + "\n";
    }
  } else if (state.finished) {
    containerHTML = "<div class='congratulation'><h2 >You won!</h2><p>Press 'Play!' to start again.</p></div>";
  } else {
    containerHTML = state.pieces.map(renderPiece).join("\n");
  }

  container.innerHTML = containerHTML;

  function renderPiece(id, index) {
    return "<div class='piece' data-index='" + index + "'>" + id + "</div>";
  }

  function updateClass(container, x, y) {
    container.className = "slidingpuzzleContainer" + x + "x" + y;
  }

  function clear(container) {
    container.innerHTML = "";
  }
}

/**
 * Generates a shuffled array of id-s ready to be rendered
 */
function generatePuzzle(n) {
  var pieces = ["blank"];
  for (var i = 0; i < n - 1; i++) {
    pieces.push(i);
  }

  return shuffleArray(pieces);

  function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
      var j = Math.floor(Math.random() * (i + 1));
      var temp = array[i];
      array[i] = array[j];
      array[j] = temp;
    }
    return array;
  }
}
body {
  font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Helvetica, Arial, sans-serif;
  font-size: 12px;
  color: #000;
}
#formatContainer {
  position: absolute;
  top: 50px;
  left: 500px;
}
#formatContainer label {
  display: inline-block;
  max-width: 100%;
  margin-bottom: 5px;
}
#formatContainer select {
  display: block;
  width: 100%;
  margin-top: 10px;
  margin-bottom: 10px;
}
#formatContainer button {
  display: inline-block;
  width: 100%;
}
.piece {
  width: 96px;
  height: 96px;
  margin: 1px;
  float: left;
  border: 1px solid black;
}
.slidingpuzzleContainer3x3,
.slidingpuzzleContainer3x4,
.slidingpuzzleContainer4x3,
.slidingpuzzleContainer4x4 {
  position: absolute;
  top: 50px;
  left: 50px;
  border: 10px solid black;
}
.slidingpuzzleContainer3x3 {
  width: 300px;
  height: 300px;
}
.slidingpuzzleContainer3x4 {
  width: 300px;
  height: 400px;
}
.slidingpuzzleContainer4x3 {
  width: 400px;
  height: 300px;
}
.slidingpuzzleContainer4x4 {
  width: 400px;
  height: 400px;
}
.congratulation {
  margin: 10px;
}
}
<body onload="initGame();">
  <div id="slidingpuzzleContainer"></div>
  <form id="formatContainer">
    <label for="format">select format:</label>
    <select name="format" id="format" size="1">
      <option value="" selected="true" disabled="true"></option>
      <option value="3x3">Format 3 x 3</option>
      <option value="3x4">Format 3 x 4</option>
      <option value="4x3">Format 4 x 3</option>
      <option value="4x4">Format 4 x 4</option>
    </select>
    <button type="submit" disabled="true">Play!</button>
  </form>
</body>

这里我们有启动一切的 initGame() 函数。调用时它将创建游戏的初始状态(我们有默认的大小和状态属性需要关心),在控件上添加侦听器并使用当前状态调用 render() 函数。

initGameControls() 为字段上的点击设置一个侦听器,它将 1) 调用 movePiece() 如果前者在某个地方,它会尝试将点击的部分移动到空白处,2) 检查如果在 checkFinish() 完成移动游戏后,3) 使用更新的状态调用 render()

现在 render() 是一个非常简单的函数:它只是获取状态并相应地更新页面上的 DOM。

实用函数 initFormatControl() 处理表单上的点击和更新以选择字段大小,当按下 'Play!' 按钮时将生成字段上的初始顺序并调用 render() 新状态。

这种方法的主要好处是几乎所有功能都相互分离:您可以调整逻辑以在目标片段周围找到空白 space,例如,允许交换具有相邻 ID 的片段,甚至渲染、初始化和点击处理的功能都将保持不变。