2048:具有lodash / fp的map中的reduceRight的奇怪行为

时间:2019-05-05 15:18:43

标签: javascript functional-programming lodash 2048

以下代码是尝试使用lodash- fp 制作我的2048版本(游戏)的开始。我已经习惯了定期聊天,但这是我第一次接触fp风味。

它使用两个功能来实现将一排瓷砖向右推的动作:

  • slide将行向右推,前提是有空白(由值0表示)。实际上,这等于将所有零都放在左侧。
  • merge合并成对的相同值的连续图块,从而生成一个空白空间和一个新的值翻倍的图块。 (在slide之后第二次调用merge,以清理该步骤可能产生的零)。

函数使用_.reduceRight方法,该方法从右到左在图块上进行迭代。

import _ from "lodash/fp";


let game = [[2, 2, 0, 0], [4, 0, 4, 0], [8, 0, 0, 8], [16, 16, 0, 0]]; // Sample state

let slide = _.flow(
  _.reduceRight(
    (v, acc) =>
      v === 0 ? [_.concat(acc[0], v), acc[1]] : [acc[0], _.concat(v, acc[1])],
    [[], []]
  ),
  _.flatten
);

let merge = _.flow(
  _.reduceRight(
    (v, acc) => {
      acc[0].unshift(v);
      if (acc[0].length === 2) {
        if (acc[0][0] === acc[0][1]) {
          acc[1] = _.concat(0, _.concat(acc[0][0] + acc[0][1], acc[1]));
          acc[0] = [];
        } else {
          acc[1] = _.concat(acc[0].pop(), acc[1]);
        }
      }
      return acc;
    },
    [[], []]
  ),
  _.flatten
);

// Moves one line
let moveLine = _.flow(
  slide,
  merge,
  slide
);

// Moves the 4 lines
let moveBoard = _.map(moveLine);

moveLine似乎运行良好。例如,moveLine(game[0])[2, 2, 0, 0]转换为[0, 0, 0, 4]

奇怪的是,moveBoard(game)(将moveLine映射到4行)给出了一个奇怪的结果,每次迭代都变得更长,就像前面步骤的结果被附加了一样:

[
  [0,0,0,4],
  [0,0,0,0,0,0,8,4],
  [0,0,0,0,0,0,0,0,0,16,8,4],
  [0,0,0,0,0,0,0,0,0,0,0,0,32,16,8,4]
]

我发现问题来自merge,但我真的看不到这里是怎么回事。

2 个答案:

答案 0 :(得分:1)

更改move方法以删除前4个元素。

出于某种奇怪的原因,merge的每次迭代

ReduceRight的acc [1]作为其中的上一个数组

此修补程序将对其进行修复

let take = arr => arr.slice(0,4);

// Moves one line

let moveLine = _.flow(
  slide,
  merge,
  take
);

这是带有实现的Runkit

https://runkit.com/naor-tedgi/5ccf0862b0da69001a7db546

答案 1 :(得分:1)

我打开了GitHub问题,其中包含问题的简化版本:https://github.com/lodash/lodash/issues/4287

lodash的创建者John-David Dalton给出的简短答案:

  

使用fp合成,累加器不会为每个组成的reduce函数创建新鲜的对象。这就是为什么使用fp.concat()创建无突变版本的累加器的原因。