如何递归地组织元素(俄罗斯方块)

时间:2016-08-05 23:15:29

标签: jquery algorithm recursion recursive-backtracking

我正在学习递归,但我需要一个关于如何开始制作算法的参考。我需要组织块来使用所有部分,最大可能填充板。谢谢大家。

enter image description here

2 个答案:

答案 0 :(得分:1)

递归有两个主要的想法,第一个是每个步骤的问题(所以在这种情况下是董事会)你解决问题应该变得更小。第二个重要的想法是每个步骤都是一样的。

因此,在这种情况下,您可以放置​​一块,然后在板上再次调用该功能,同时移除放置的部件。让我们再深入了解它们。

  1. 每次放置一块并调用该功能时,您可以放置​​一块的位置数量会减少。
  2. 每次再次调用此功能时,您仍然只是想放置磁贴。因此,尽管问题空间较小,问题仍然保持一致。
  3. 希望这有帮助!

答案 1 :(得分:1)

这是一个相当幼稚的算法实现,可以帮助您入门。

它正在寻找一个完美的解决方案(董事会完全填满),并在找到一个解决方案后立即退出。这将按照您的示例板的预期工作,但它可能会永远运行其他没有简单完美解决方案的板,或根本没有完美的解决方案。

更好的算法是:

  • 寻找适合任何电路板的最佳解决方案(不仅仅是完美的电路板)
  • 使用更多启发式方法来加快搜索速度

此算法中唯一的改进是使用哈希表来避免两次访问同一个板,当两个不同的移动组合产生相同的配置时。

电路板的每一行都表示为一个字节,每一部分表示为2x2位。



var b = [
      // initial board
      0b00000000,
      0b00000000,
      0b00000100,
      0b00000000,
      0b00000000,
      0b00000000,
      0b00000000,
      0b00000000
    ],
    piece = [
      // bitmasks of pieces as [ top_bitmask, bottom_bitmask ]
      [ 0b11, 0b01 ], [ 0b11, 0b10 ], [ 0b01, 0b11 ], [ 0b10, 0b11 ]
    ],
    // hash table of visited boards
    hash = {},
    // statistics
    node = 0, hit = 0;

function solve(sol) {
  var x, y, p, s;
  
  // compute hexadecimal key representing the current board
  var key =
      ((b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0).toString(16) + '-' +
      ((b[4] | (b[5] << 8) | (b[6] << 16) | (b[7] << 24)) >>> 0).toString(16);

  node++;
  
  if(hash[key]) {
    // abort immediately if this board was already visited
    hit++;
    return false;
  }
  if(key == 'ffffffff-ffffffff') {
    // return the current solution if the board is entirely filled
    return sol;
  }
  
  // save board in hash table
  hash[key] = true;

  // for each position and each type of piece ...
  for(y = 0; y < 7; y++) {
    for(x = 0; x < 7; x++) {
      for(p = 0; p < 4; p++) {
        // ... see if we can insert this piece at this position
        if(!(b[y] & (piece[p][0] << x)) && !(b[y + 1] & (piece[p][1] << x))) {
          // make this move
          b[y]     ^= piece[p][0] << x;
          b[y + 1] ^= piece[p][1] << x;

          // add this move to the solution and process recursive call
          s = solve(sol.concat(x, y, p));
          
          // unmake this move
          b[y]     ^= piece[p][0] << x;
          b[y + 1] ^= piece[p][1] << x;

          // if we have a solution, return it
          if(s) {
            return s;
          }
        }
      }
    }
  }  
  return false;
}

function display(sol) {
  var n, x, y, html = '';

  for(n = 0; n < 64; n++) {
    html += '<div class="cell"></div>';
  }
  $('#container').html(html);
  
  for(n = 0; n < sol.length; n += 3) {
    for(y = 0; y < 2; y++) {
      for(x = 0; x < 2; x++) {
        if(piece[sol[n + 2]][y] & (1 << x)) {
          $('.cell').eq(7 - sol[n] - x + (sol[n + 1] + y) * 8)
            .addClass('c' + sol[n + 2]);
        }
      }
    }
  }
}

setTimeout(function() {
  display(solve([]));
  console.log(node + ' nodes visited');
  console.log(hit + ' hash table hits');
}, 500);
&#13;
#container { width:160px; height:160px }
.cell { width:19px; height:19px; margin:1px 1px 0 0; background-color:#777; float:left }
.c0 { background-color:#fb4 }
.c1 { background-color:#f8f }
.c2 { background-color:#4bf }
.c3 { background-color:#4d8 }
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">Searching...</div>
&#13;
&#13;
&#13;