내 맥락 에서이 난수 생성을 개선하는 방법은 무엇입니까?


11

내 게임에서 화면 상단에 단어가 있고, 글자가 위에서 아래로 떨어지고 있으며 사용자는 글자를 터치하여 단어를 완성해야합니다.

현재 나는 무작위로 문자를 생성하고 있습니다 (실제로 임의의 숫자와 숫자는 문자 배열의 색인입니다 (예 : 0 = a, 1 = b)). 그러나 문제는 모든 필요한 문자를 완성하는 데 너무 많은 시간이 걸린다는 것입니다 워드.

내가 원하는 것은 내가 생성하는 임의의 숫자가 필요한 문자를 더 자주 생성해야하므로 플레이어가 하루 종일 단어를 완성하지 않아도됩니다.

나는 다음과 같은 방법을 시도했다 :

  1. 단어의 모든 문자를 감지하고 (단어 길이는 항상 6 문자입니다) 길이가 6 인 인덱스 배열을 생성하고 배열의 각 인덱스를 문자 2에서 문자 + 2까지의 난수에 할당하고 결국에는 무작위로 하나의 인덱스를 선택하십시오 배열에서 표시합니다.

  2. selector == 0 인 경우 무작위로 생성 된 값이 [0..2] 범위에있는 선택기 변수를 사용하여 단어를 생성하고 한 문자를 임의로 선택하는 문자를 감지하고, 그렇지 않으면 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.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 번의 누락 후 단어를받을 확률이 1.0입니다.)

마지막으로, 단어에서 문자를 선택하는 방법을 고려해야합니다. 플레이어에게 실제로 필요한 글자를 제공하려면 세트에서 글자를 가져와야합니다.

예를 들어 단어가 "test"이고 플레이어에 이미 's'가 있으면 필요하지 않기 때문에 다른 's'를주고 싶지 않습니다!

여기에서 나머지는 디자인에 맞게 조정됩니다.


와! 내일 아침에 분석법을 테스트하고 작동한다고 생각합니다.이 mehod를 테스트하면 더 많은 피드백을 제공 할 것입니다. 그러한 답변에 대단히 감사합니다.
Daniyal Azram 2016 년

4
통계! 게임 디자이너 또는 프로그래머로서 통계는 매우 가치가 있습니다. 최소한 확률에 대한 이해 (그리고 그것들을 결합하는 방법)는 매우 유용합니다.
ACEfanatic02 년

1
같은 것을 제안하러 오십시오. 좋은 대답입니다. 또한 이와 같은 솔루션은 난이도를 도입하는 방법이 될 수 있습니다. 쉬움 = 0.5, 중간 = 0.25, 어려움 = 0.10. 기타
Tasos

나는 이것이 무작위가 아니라는 것에 동의하지 않습니다. 이것은 무작위이며, 부분 분포 일 뿐이며 일반적으로 균일 분포를 생각합니다. 그리고 당신의 아이디어에 추가하기 위해 나는 "단어에서 임의의 문자를 골라내는 것"보다 더 나아가고 자합니다. 예를 들어 "mississippi"에는 더 많은 것이 필요하므로 더 많이 선택하십시오.
Blaine


21

단어가 사용되는 언어의 빈도에 따라 모든 글자의 확률에 가중치를 부여 할 수 있습니다. 좋은 지침은 글자 맞추기입니다 . 예를 들어 영어 버전은 E가 12 개이지만 Z는 1 개, 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 사이의 난수를 생성하고, 임의의 숫자에서 각 문자의 빈도를 빼기까지 표를 반복 할 수 있습니다. 0 또는 음수가됩니다. 표에서 가장 일반적인 문자를 먼저 정렬하여이를 최적화 할 수도 있습니다. 또는 별칭 방법 과 같은 것을 사용 하여 테이블을 완전히 반복하지 않도록하십시오.
Ilmari Karonen

4
이렇게해도 문제가 해결되지 않습니다. 문제는 사용자 게임을 끝내기 위해 특정 글자가 필요하다는 것 입니다. Z가 필요하다고 해? 그럼 뭐야? 이로 인해 희귀 한 글자가 사용자를 더욱 좌절시키기 어렵게 만듭니다.
AmazingDreams 2016 년

@AmazingDreams는 좋은 점을 지적하지만 조금 수정할 수 있으므로 필요한 알파벳에 더 많은 무게를 할당하고 다른 사람들에게는 더 적은 무게를 할당합니다. 나는 이것이 따라야 할 아주 좋은 개념이라고 말해야한다.
Daniyal Azram

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';
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.