2048:使用 lodash/fp 的地图中 reduceRight 的奇怪行为

Posted

技术标签:

【中文标题】2048:使用 lodash/fp 的地图中 reduceRight 的奇怪行为【英文标题】:2048 : Strange behaviour of reduceRight in map with lodash/fp 【发布时间】:2019-09-23 09:34:03 【问题描述】:

以下代码是尝试使用 lodash-fp 制作我的 2048 版本(游戏)的开始。我习惯了普通的lodash,但这是我第一次接触fp的味道。

它实现了将一行的瓦片向右推的动作,使用两个函数:

slide 将行推到右侧,前提是有空格(由值 0 表示)。实际上,这相当于把所有的零都放在左边。 merge 合并成对的具有相同值的连续图块,生成一个空白区域和一个具有双倍值的新图块。 (slidemerge 之后第二次被调用以清除该步骤可能产生的零)。

这些函数使用_.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,但我真的看不出这里发生了什么。

【问题讨论】:

请详细说明滑动和合并应该如何工作。逻辑的例子会很棒。 用一个例子来总结一下逻辑:Starting with: [8, 8, 2, 2], slide: => [8, 8, 2, 2] (什么都不做,因为有没有零)_.reduceRight(从 3 到 0 的步骤):步骤 3 => [2][],步骤 2 => [2,2][] => [][0, 4],步骤 1 => [ 8][0, 4], 步骤 0 => [8, 8][0, 4] => [][0, 16, 0, 4] _.flatten: => [0, 16, 0, 4] slide: => [0, 0, 16, 4] 根据 2048 年的规则,这是向右推行的预期结果。 【参考方案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

【讨论】:

【参考方案2】:

我已经打开了一个带有简化版问题的 GitHub 问题:https://github.com/lodash/lodash/issues/4287。

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

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

【讨论】:

以上是关于2048:使用 lodash/fp 的地图中 reduceRight 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

进阶学习3:函数式编程FP——函数的组合组合函数模拟Lodash fp模块PointFree

markdown lodash / fp设置和流程

函数式 js 接口实现原理,以及 lodash/fp 模块

Lodash的使用

Fusion Tables 图层 URL 请求限制(2048 个字符)

2048