在我的上下文中,如何改善随机数的生成?


11

在我的游戏中,屏幕顶部有一个单词,字母从顶部开始下雨,用户必须触摸字母才能完成单词。

目前,我正在随机生成字母(实际上随机数和数字是字母数组的索引。例如:0 = a,1 = b),但问题是花太多时间才能获取所有必需的字母才能完成字。

我想要的是,我生成的随机数应该更频繁地生成所需的字母,这样玩家就不必花一整天的时间来完成一个单词。

我尝试了以下方法:

  1. 检测单词中的所有字母(单词始终为6个字母),生成长度为6的索引数组,将数组的每个索引分配给从letter-2到letter + 2的随机数,最后随机选择一个索引从数组中显示出来。

  2. 有一个选择器变量,其值在[0..2]范围内,是随机生成的,如果选择器== 0,则检测组成该单词的字母并随机选择一个字母,否则从az中随机获取任何字母。

这两种方法都没有为我提供任何帮助。如果您能帮助我,我将非常高兴。

感谢您阅读本文,希望您理解该问题,我们正在等待答复。


2
“这两种方法都没有给我任何帮助”为什么不呢?这些方法不适用于什么?
Vaillancourt

我不知道为什么,但是要获得所有需要的字母仍然花费太多时间(如1分钟)。
Daniyal Azram

@DaniyalAzram如果这些字母出现的频率不够高,您可能应该增加频率,因为听起来这就是您的问题所在。
JFA

Answers:


21

您实际上并不需要随机分布。我明确指出这一点,因为我们认为设计的“随机性”通常不是真正的随机性。

现在,考虑到这一点,让我们添加一些调整值-在设计感到“正确”之前,您将一直使用这些东西。

ChooseLetter() {
    const float WordLetterProbability = 0.5f;
    if (Random.NextFloat01() < WordLetterProbability) {
        // Pick a random letter in the word
    }
    else {
        // Pick a random letter *not* in the word
    }
}

机率控制着给定的ChooseLetter呼叫给您一个单词字母的可能性-值为0.5时,您大约每隔一段时间就会收到一个单词字母。值为0.25时,四分之一就是单词字母,依此类推。

这仍然有点简单-因为随机性是随机的,所以您实际上无法保证单词之间的间隔时间。(从理论上讲,没有单词字母就可以永远消失,这是非常非常不可能的。)相反,我们可以增加一个因素来增加每次收到单词字母的概率:

const float BaseWordLetterProbability = 0.5f;
const float WordLetterProbabilityIncrease = 0.25f;
float WordLetterProbability = BaseWordLetterProbability;
ChooseLetter() {
    if (Random.NextFloat01() < WordLetterProbability) {
        // Pick a random letter in the word
        WordLetterProbability = BaseWordLetterProbability;
    }
    else {
        // Pick a random letter *not* in the word
        WordLetterProbability += WordLetterProbabilityIncrease;
    }
}

好吧,所以现在我们在没有单词字母的情况下不要超过两个字母。(因为在两次未命中之后,我们得到单词字母的概率为1.0。)

最后,我们需要考虑选择单词中的字母是如何工作的。为了向玩家提供他们实际需要的字母,我们需要在获得字母时将其从集合中删除。

例如,如果单词是“ test”,并且玩家已经有“ s”,我们就不想再给他们一个“ s”,因为他们不需要它!

从这里开始,其余部分将进行调整以适合您的设计。


哇!:p我什至想出了什么方法?非常感谢您的回答。
Daniyal Azram

4
统计!作为游戏设计师或程序员,统计数据非常值得学习。至少,了解概率(以及如何将其组合)非常有用。
ACEfanatic02年

1
来建议同样的事情。好答案。还请记住,这种解决方案可能是引入难度级别的一种方法。容易= 0.5,中等= 0.25,困难= 0.10。等
Tasos

我不同意这不是随机的。这是随机的,只是分段分布,而我们通常认为是均匀分布。为了增加您的想法,我将进一步介绍,而不只是“在单词中随机选择一个字母”,而是按照出现频率最高的字母进行分配。例如,“ mississippi”需要更多的,而我则选择更多。
布莱恩


21

您可以根据单词所用语言的出现频率来加权所有字母的概率。一个很好的指南是拼字游戏。例如,英文版具有12个E,但只有一个Z和一个Q。

一种简单的实现方法是,将所有字母放在一个连续的字符串中,每个字母按需要出现,然后让您的RNG从随机位置取一个字母。伪代码示例:

const String letters = "AAAAAAAAABBCCDDDDEEEEEEEEEEEEFFGGGHHIIIIIIIIIJ/*...and so on...*/"

char randomLetter = letters[randomIntegerBetween(0, letters.length - 1)];

2
+1这是一个很好的概念,但是我怀疑有一个更优雅的实现。
Evorlor


为了获得更细粒度的分布,您可以存储一个按比例缩放的字母频率表,使它们的总和为1,从0到1生成一个随机数,然后遍历该表,从随机数中减去每个字母的频率,直到它变为零或负数。您甚至可以通过在表格中首先对最常见的字母进行排序来对此进行优化。或使用类似alias方法的方法来避免完全遍历表。
Ilmari Karonen

4
这不会解决问题。问题是用户需要特定的字母才能完成游戏。说他们需要Z吗?然后怎样呢?这只会使稀有字母变得更难使用户感到沮丧。
AmazingDreams

@AmazingDreams指出了一件好事,但我们可以对其进行一些修改,因此我将为所需的字母分配更多的权重,而为其他字母分配更少的权重。我必须说这是一个很好的概念。
Daniyal Azram '16

4

这是使用一个k可以调整的参数来改善它的方法。

不仅仅是选择随机字母:

  1. 选择一个随机字母 A
  2. 选择一个随机数 X
  3. 如果X > k A不在[list of remaining needed letters],请在1再试一次。

越小k,最后一封信越经常A是实际需要的一封信。

要调整算法,请使用的任何值k例如 k = 0.5。如果您发现游戏太难了,请尝试其他方法0.4,直到找到合理的价值为止。这也直接给您带来了难度设置,例如,您可能希望随着玩家在游戏中的前进而增加难度


感谢您的回答,但这似乎就像ACEfanatic02的回答。
Daniyal Azram

3

确保所需字母在给定时间内显示的一种简单方法是,使用单词中的字母和其余字母(可能重复)填充数组,然后随机地对数组进行洗牌(c ++具有std :: random_shuffle在标准库中,如果您使用其他语言,则不难实现)。

如果您希望单词中的字母更快地显示,请将更多的单词字母副本放入数组中。


0

如果您使用的是C ++,则可以使用已经存在的发行版 http://en.cppreference.com/w/cpp/numeric/random/piecewise_constant_distribution

它还具有摊销的恒定时间复杂度,这比幼稚的方法要好。例:

#include <iostream>
#include <string>
#include <map>
#include <random>
#include <numeric>

int main()
{
    constexpr double containedLetterWeight = 3.0;
    constexpr int iterations = 10000;
    std::string word = "DISTRIBUTION";

    std::mt19937 rng(123);

    std::vector<double> values('Z' - 'A' + 2);
    std::iota(values.begin(), values.end(), 0.0);

    std::vector<double> weights('Z' - 'A' + 1, 1.0);
    for(const auto& c : word) weights[c - 'A'] = containedLetterWeight;

    std::piecewise_constant_distribution<> dist(values.begin(), values.end(), weights.begin());

    std::map<char, int> results;
    for(int n = 0; n < iterations; ++n)
    {
        ++results[static_cast<char>(dist(rng)) + 'A'];
    }
    for(const auto& p : results)
    {
        std::cout << p.first << ' ' << static_cast<float>(p.second) / iterations << '\n';
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.