私のコンテキストでこの乱数生成を改善するにはどうすればよいですか?


11

私のゲームでは、画面の上部に単語があり、文字が上から降りてきており、ユーザーは文字をタッチして単語を完成させる必要があります。

現在、ランダムに文字を生成しています(実際にはランダムな数字と数字が文字の配列のインデックスです。例:0 = a、1 = b)。問題は、必要なすべての文字を取得するのに時間がかかりすぎることです。語。

私が欲しいのは、プレイヤーが1つの単語を完了するために1日中費やす必要がないように、生成する乱数によって必要な文字がより頻繁に生成されることです。

私は以下の方法を試しました:

  1. 単語のすべての文字を検出し(単語は常に6文字長)、長さ6のインデックスの配列を生成します。配列の各インデックスを文字2から文字+2までの乱数に割り当て、最後にランダムに1つのインデックスを選択します表示する配列から。

  2. 値が[0..2]の範囲にあるセレクター変数をランダムに生成します。セレクター== 0の場合、単語を構成する文字を検出し、ランダムに1文字を選択します。それ以外の場合は、azから任意のアルファベットをランダムに取得します。

これらの方法はどちらも私に何の助けも提供していません。あなたが私を助けることができれば私はとても幸せです。

お読みいただきありがとうございます。ご理解いただき、ご回答をお待ちしております。


2
「これらのメソッドの両方を任意の助けを私に提供していない」のはなぜか?これらの方法で何がうまくいかなかったのですか?
Vaillancourt

理由はわかりませんが、すべてのアルファベットを取得するのに1分ほどの時間がかかります。
Daniyal Azram 2016年

@DaniyalAzramこれらの文字が十分に頻繁に表示されない場合は、おそらく頻度をもう少し上げる必要があります。
JFA

回答:


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の場合、おおよそ1時間おきに単語の文字が得られます。0.25では、4つに1つは単語の文字などになります。

これはまだ少し単純化されています-ランダム性はまあまあランダムなので、単語の文字の間を移動する時間について実際に保証することはできません。(理論的には、単語の文字なしで永遠に行くことができます。それは非常にまれです。)代わりに、単語の文字を取得しないたびに、単語の文字の確率を上げるための係数を追加できます。

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;
    }
}

さて、今私たちは単語の文字なしで2文字以上行くことはありません。(2つのミスの後、単語の文字を取得する確率は1.0になるためです。)

最後に、一言で文字を選択することがどのように機能するかを考慮する必要があります。プレイヤーに実際に必要な文字を提供するには、セットから文字を削除する必要があります。

たとえば、単語が「test」であり、プレーヤーにすでに「s」が含まれている場合、必要がないため、別の「s」を与えたくありません!

ここから、残りはあなたのデザインに合うように調整されます。


うわー!どのようにしてそれを思いついたのですか?そんな回答ありがとうございました。
Daniyal Azram 2016年

4
統計!ゲームデザイナーやプログラマのいずれかとし、統計がある非常に価値がある学習。少なくとも、確率(およびそれらを組み合わせる方法)を理解することは非常に役立ちます。
ACEfanatic02

1
同じことを提案しに来てください。素晴らしい答え。また、このような解決策は難易度レベルを導入する方法になる可能性があることも覚えておいてください。Easy = 0.5、medium = 0.25、hard = 0.10。etc
タソス

これはランダムではないことに同意しません。これはランダムであり、それは単に区分的分布ですが、通常は均一分布を考えます。そして、あなたの考えを追加するために、私は単に「単語の中でランダムな文字を選ぶ」よりも先に進みたいと思います。私は、それを最も多く出現する文字で分配します。たとえば、 "mississippi"にはsとiがもっと必要なので、もっと多くを選択します。
ブレイン、2016年


21

すべての文字の確率は、単語が使用されている言語で出現する頻度に応じて重み付けできます。良いガイドラインはスクラブルセットです。たとえば、英語バージョンには12個のEがありますが、ZとQはそれぞれ1つだけです。

これを実装する簡単な方法は、すべての文字を連続した文字列に入れて、各文字が必要な頻度で出現し、RNGがランダムな位置から文字を取得するようにすることです。擬似コードの例:

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

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

2
+1これは良いコンセプトですが、もっとエレガントな実装があると思います。
Evorlor 2016年


よりきめの細かい分布の場合、合計が1になるようにスケーリングされた文字頻度のテーブルを保存して、0から1までの乱数を生成し、乱数から各文字の頻度を減算するまでテーブルをループできます。ゼロまたは負になります。最も一般的な文字を最初にテーブルで並べ替えることで、これを最適化することもできます。または、エイリアスメソッドのようなものを使用して、テーブル全体をループしないようにします。
Ilmari Karonen

4
これは問題を解決しません。問題は、ユーザーゲームを完了するために特定の文字を必要とすることです。Zが必要だと思いますか?それで?これは、ユーザーをさらに不満にさせるために、まれな文字を難しくするだけです。
AmazingDreams 2016年

@AmazingDreamsは良いことを指摘していますが、少し変更して、必要なアルファベットにより多くの重みを割り当て、他のアルファベットにはより少ない重みを割り当てることができます。これは従うべき非常に良い概念だと言わざるを得ません。
Daniyal Azram 2016年

4

kこれは、調整可能な1つのパラメーターを使用して改善する1つの方法です。

ランダムな文字を選ぶだけではなく、

  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 2016年

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';
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.