有没有办法改善算法?

时间:2019-07-13 16:28:06

标签: javascript algorithm

我正在编写一个简单的游戏,其中玩家拥有不同颜色的瓷砖区域。当拾取类似块的块时,将其删除。剩余的图块向下滑动到删除的图块留下的空白处。

字段本身是2d数组,而tile是tileSpr [x] [y]

删除图块时,其值为null:

tileSpr[x][y] = null;

现在我有一个非常简单的函数,该函数返回需要向下移动的瓷砖阵列以及它们下面有多少个“孔”:

whichTilesNeedMove() {
    const tilesToMove = [];
    for (let i = 1; i < CONFIG.maxRows; i++) {
      for (let j = 0; j < CONFIG.maxCols; j++) {
        if (this.tilesSpr[i][j] !== null) {
          let emptySpace = 0;
          for (let m = i - 1; m >= 0; m--) {
            if (this.tilesSpr[m][j] === null) {
              emptySpace++ ;
            }
          }
          if (emptySpace > 0) {
            tilesToMove.push({ tile: this.tilesSpr[i][j], emptySpace });

            this.tilesSpr[i - emptySpace][j] = this.tilesSpr[i][j];
            this.tilesSpr[i - emptySpace][j].rowIndex = i - emptySpace;
            this.tilesSpr[i][j] = null;
          }
        }
      }
    }
    return tilesToMove;
  }

感觉该函数中使用的算法不是最佳算法,因为它必须遍历整个2d数组。不幸的是,因为我是编程方面的新手,所以没有比我更好的事情了。

您能建议一种更理想的方法吗?

2 个答案:

答案 0 :(得分:4)

我将2D数组组织为(而不是行)的数组,其中列数组的第一个条目是底部的正方形。然后,当磁贴必须消失时,不要分配null,而是在相应的列上执行拼接。这将自动向下移动上部砖块(在模型中)。如果确实需要,则可以将null推送到该列以恢复其中的条目总数,但实际上没有理由。

这是一个小演示。它使用CSS transition来为水滴设置动画,但这仅仅是装饰。它不包含查找相同颜色的图块的逻辑,而只是删除了您单击的图块,并相应地更新了游戏区域。

我要说的核心是简化pushsplice调用以保持模型(game.columns)更新的目的。

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const transition = (elem, marginTop) => new Promise(resolve => {
    elem.style.marginTop = marginTop + "px";
    elem.ontransitionend = resolve
});

const game = {
    grid: document.querySelector("#grid"),
    columns: Array.from({length: 10}, () => []),
    async drop(x, color) {
        if (this.columns[x].length >= 10) return;
        const y = 10-this.columns[x].length;
        const tile = document.createElement("span");
        this.grid.append(tile);
        Object.assign(tile.style, { left: x * 20 + "px", backgroundColor: color });
        this.columns[x].push(tile);
        await delay(1);
        return transition(tile, y*20);
    },
    async remove(x, y) {
        if (y >= this.columns[x].length) return;
        this.columns[x].splice(y, 1)[0].remove();
        let p = Promise.resolve();
        for (let tile of this.columns[x].slice(y)) {
            p = transition(tile, (parseInt(tile.style.marginTop)+20));
        }
        return p;
    }
};

game.grid.onclick = function (e) {
    const x = Math.floor((e.clientX - this.offsetLeft) / 20);
    const y = 9 - Math.floor((e.clientY - this.offsetTop) / 20);
    game.remove(x, y)
}

async function initGame() {
    const randInt = (len) => Math.floor(Math.random() * len);
    const colors = ["red", "blue", "green", "yellow", "grey", "cyan"];
    for (let i = 0; i < 70; i++) {
        game.drop(randInt(10), colors[randInt(colors.length)]);
        await delay(5);
    }
}

initGame();
body { margin: 0 }
#grid>span { 
    position: absolute; 
    border: 1px solid; 
    display: inline-block; 
    width: 19px; 
    height: 19px;
    top: -20px;
    transition: margin-top 100ms linear;
}
#grid { 
    background-size: 20px 20px;
    background-image: linear-gradient(to right, lightgrey 1px, transparent 1px), 
                      linear-gradient(to bottom, lightgrey 1px, transparent 1px);
    display: inline-block;
    width: 201px;
    height: 201px;
    position: relative;
}
<div id="grid"></div>

注意:dropremove方法返回的承诺会在相应的动画完成时解析,但是我在这段代码中并未真正使用该返回值。

答案 1 :(得分:1)

您可以从greates索引中进行迭代,查看一列中是否有更多的null(此处仅用于格式化为零)值,然后将最大的上限值替换为零,将较低的下标替换为该值。

var array = [
        [1, 1, 1, 1, 1],
        [2, 2, 0, 0, 2],
        [3, 0, 0, 0, 3],
        [4, 4, 4, 0, 0]
    ],
    i = array.length,
    j,
    l;

array.forEach(a => console.log(...a));    
console.log('to');

while (--i) {
    for (j = 0; j < array[0].length; j++) {
        l = i;
        while (l > 0 && array[l][j] === 0) l--;
        if (l !== i) {
            array[i][j] = array[l][j];
            array[l][j] = 0;
        }
    }
}

array.forEach(a => console.log(...a));    
.as-console-wrapper { max-height: 100% !important; top: 0; }