【问题标题】:Looking for a better way to reduce array and determine if numbers are in order寻找一种更好的方法来减少数组并确定数字是否有序
【发布时间】:2020-01-05 17:20:35
【问题描述】:

const dice = [1,3,4,5,6]
const score = straightScore(dice,4)

    function straightScore(dice, sizeOfStraight) {
        let score = 0
        sizeOfStraight > 4 ? score = 40 : score = 30
        dice.sort( (a, b) => a-b )
        // filter to eliminate duplicates
        const filteredDice = dice.reduce( (acc, die) => {
            if ( acc.indexOf(die) === -1 ) acc.push(die)
            return acc
        }, [] )
        //determine straight
        const straightFinder = filteredDice.reduce( (acc, die) => {
            const lastNumInArray = acc.slice(-1)[0]
            // here is my hack if the small straight starts with 3 and the last die             is a 1
            if ( die - lastNumInArray === 2) acc = [die]
            if ( lastNumInArray === undefined || die - lastNumInArray === 1 )                     acc.push(die)
            return acc
        }, [] )
        if (straightFinder.length >= sizeOfStraight) return score
        return 0
    }

    console.log(score)

我得到了这个工作,但感觉很hacky。任何想法将不胜感激。

我正在尝试制作一个基本的 Yahtzee 游戏。确定是否滚动顺子是我卡住的地方。它基本上是有效的,但如果它是一个小的顺子(五个骰子中的一个连续 4 个)从 3 - 6 并且第五个骰子是 1,我的减少将无法正常工作。它总是解析为 1 项数组。我可以在我的逻辑中看到问题,所以我在其中投入了一些小技巧以使其工作,但我觉得必须有十几种更好的方法。这是我的代码。感谢观看。

骰子是一个由 5 个数字 1-6 组成的数组,代表骰子,sizeOfStraight 只是为了让我可以将它重用于大顺子。不过,问题只出现在小顺子上,所以你可以为此投入 4。

输入骰子 = [1, 3, 4, 5, 6] 输出(无,只是返回,因为 StraightFinder.length = 1)

【问题讨论】:

  • 请添加输入输入与预期输出的示例。
  • 除了@OriDrori 所说的,这是纯JavaScript。付出一点努力并创建一个 sn-p,以便我们可以轻松地对其进行测试/修复。
  • 意外并不完全正确。当我开始输入问题时确实如此。然后我弄清楚发生了什么。我只是在寻找更好的方法。在我在问题中解释的情况下,出乎意料的输出是第二次减少将其减少到一个包含数字 1 的 1 项数组。

标签: javascript arrays reduce


【解决方案1】:

在最后的操作中你真的不需要reduce。只需检查索引 0 和索引 3 处的排序骰子。如果后者的值比第一个大 3,则前 4 个排序骰子代表小直。可以在索引 1 和索引 4 处重复相同的操作。对于小顺子,没有其他位置可能。大顺子只能从索引 0 开始,因此只需要一次过牌。

注意:可以在临时 Set 的帮助下提取唯一值。

const dice = [1, 3, 4, 5, 6];
const score = straightScore(dice, 4);

function straightScore(dice, sizeOfStraight) {
    let score = 0;
    sizeOfStraight > 4 ? score = 40 : score = 30;
    dice.sort( (a, b) => a-b );
    // duplicates can be eliminated with a Set:
    const filteredDice = [...new Set(dice)];
    // determine straight: only two locations are of interest (at most)
    if (filteredDice[sizeOfStraight-1] - filteredDice[0] === sizeOfStraight-1) return score;
    if (filteredDice[sizeOfStraight] - filteredDice[1] === sizeOfStraight-1) return score;
    return 0;
}
 
console.log(score);

【讨论】:

  • 非常聪明。谢谢你。使用 Set 更干净。我也喜欢判断顺子的逻辑。这比我的烂摊子更直接。谢谢!!
【解决方案2】:

也许这个答案对您的需求有点过分,但可能会激发您的灵感。一般来说,我会创建一个滚动值的“直方图”,然后寻找最长的连续“命中”序列来找到最长的直线。

方法一:

假设我们滚动了dice = [6, 3, 1, 4, 3]。 “直方图”如下所示:

0 - false (there's no dice roll 0)
1 - true
2 - false
3 - true
4 - true
5 - false
6 - true
7 - false (there's no dice roll 7)

索引 0 和 7 可用作边界,它们保证始终为假(这简化了检测从 1 开始或以 6 结束的直线)。可以这样创建:

Array(8).fill(false).map((_, i) => dice.indexOf(i) >= 0)
-> [false, true, false, true, true, false, true, false]

现在我们需要找到最长的真值序列的长度。让我们遍历直方图,检测从 false 到 true(直接开始)和返回(直接结束)的变化:

function findStraights(dice) {

    const histogram = Array(8).fill(false).map((_, i) => dice.indexOf(i) >= 0)
    let straights = [];
    let start = 0;

    for (let i = 1; i < 8; i++) {

        if (histogram[i - 1] === histogram[i])
            continue;

        if (histogram[i])
            start = i
        else
            straights.push({ start: start, length: i - start })
    }

    return straights
}

console.log(findStraights([]))
console.log(findStraights([5]))
console.log(findStraights([3, 2, 1]))
console.log(findStraights([4, 5, 6, 1]))
console.log(findStraights([6, 3, 1, 4, 3]))

现在我们有了所有找到的直道的数组,找到最长的直道很简单 (sort(...)[0])。

方法二:

让我们将直方图表示为二进制数(而不是上面显示的数组),并使用一些小技巧来确定最长序列长度:

function findLongestStraight(dice) {

    let bits = dice.reduce((a, v) => a | (1 << v), 0)
    let longest = 0

    while (bits !== 0) {

        bits &= bits << 1
        longest++
    }

    return longest
}

console.log(findLongestStraight([]))
console.log(findLongestStraight([5]))
console.log(findLongestStraight([3, 2, 1]))
console.log(findLongestStraight([4, 5, 6, 1]))
console.log(findLongestStraight([6, 3, 1, 4, 3]))

第一行创建二进制数bits,其中每个位表示给定数字是否在至少一个骰子上滚动(位0始终为0,位1表示滚动1等)在我们的例子中bits = 0b01011010 = 90

while 部分使用了一个位旋转技巧,即 shortens every sequence of consecutive 1s by one 在每次迭代中。我们所做的只是计算将所有序列归零所需的迭代次数。

【讨论】:

  • 我可能会花更多的时间来找出这个答案,而不是我原来的公式......我喜欢它!!!这肯定会激励我。感谢您的反馈!现在在谷歌上搜索“什么是直方图”。
  • @JakeM Histogram 只是你创建了一个数组来跟踪,哪个值被滚动了多少次(在我们的例子中,我们只需要知道该值是否被滚动了 - 这就是我们没问题的原因用真/假而不是“命中”数)。
猜你喜欢
  • 1970-01-01
  • 2023-01-19
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
相关资源
最近更新 更多