Bağlamımda bu rasgele sayı üretimini nasıl geliştirebilirim?


11

Oyunumda ekranın üstünde bir kelime var, harfler yukarıdan aşağı yağmur yağıyor ve kullanıcının kelimeyi tamamlamak için harflere dokunması gerekiyor.

Şu anda rastgele harfler üretiyorum (aslında rastgele sayılar ve sayılar harf dizisinin dizinidir. Örneğin: 0 = a, 1 = b) ama sorun, tüm harfleri tamamlamak için çok fazla zaman almasıdır. sözcüğü.

İstediğim, oluşturduğum rasgele sayılar gerekli harfleri daha sık üretmeli, böylece oyuncu bir kelimeyi tamamlamak için bütün gün harcamak zorunda kalmaz.

Aşağıdaki yöntemleri denedim:

  1. Kelimedeki tüm harfleri tespit edin (kelime her zaman 6 harf uzunluğundadır), uzunluk 6 dizinleri dizisi oluşturun, dizinin her dizinini harf-2'den harf + 2'ye rastgele sayıya atayın ve sonunda rastgele bir dizin seçin diziden gösterilecek.

  2. Değeri [0..2] aralığında olan, rasgele oluşturulan bir seçici değişkeniniz varsa, seçici == 0 ise, sözcüğü oluşturan harfleri algılar ve rastgele bir harf seçer, aksi takdirde az'dan herhangi bir alfabe alır.

Bu yöntemlerin ikisi de bana herhangi bir yardım sağlamadı. Bana yardım edebilirsen çok mutlu olurum.

Bunu okuduğunuz için teşekkürler, umarım soruyu anladınız ve yanıtı bekliyorum.


2
"Bu yöntemlerin ikisi de bana yardım etmiyor " Neden olmasın? Bu yöntemlerle ne işe yaramadı?
Vaillancourt

Neden bilmiyorum ama gerekli tüm alfabe almak için hala 1 dakika gibi çok zaman alıyor.
Daniyal Azram

@DaniyalAzram, bu harfler yeterince sık görünmüyorsa, sık sık biraz daha artırmalısınız, çünkü probleminiz böyle görünüyor.
JFA

Yanıtlar:


21

Aslında rastgele bir dağıtım istemiyorsunuz. Bunu açıkça belirtiyorum, çünkü tasarım için "rastgele" olarak düşündüğümüz şey genellikle gerçek rastgelelik değildir.

Şimdi bunu akılda tutarak, bazı tweaking değerleri ekleyelim - bunlar tasarım "doğru" hissedene kadar uğraşacağınız şeyler.

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

Olasılık, belirli bir SelectLetter çağrısının size bir kelime mektubu verme olasılığını kontrol eder - 0,5'te kabaca bir kelime mektubu alırsınız. 0.25'te, dördünden biri kelime mektubu vb. Olacaktır.

Bu hala biraz basit - çünkü rasgelelik, rastgele , kelime harfleri arasında ne kadar süre kalacağınıza dair bir garantiniz yok. (Teorik olarak, bir kelime mektubu olmadan sonsuza kadar gidebilirsiniz , bu çok çok olası değildir.) Bunun yerine, her bir kelime almadığımızda bir kelime mektubunun olasılığını artırmak için bir faktör ekleyebiliriz:

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

Tamam, şimdi hiçbir zaman bir kelime harfi olmadan ikiden fazla harfe gitmiyoruz. (Çünkü iki özledikten sonra, 1.0 kelime kelime alma olasılığımız var.)

Son olarak, bir kelimedeki harfi seçmenin nasıl çalıştığını göz önünde bulundurmalıyız. Oyuncuya gerçekten ihtiyaç duydukları harfleri sağlamak için harfleri setten alırken çıkarmamız gerekir.

Örneğin, kelime "test" ise ve oyuncu zaten 's' ise, onlara başka bir 's' vermek istemiyoruz, çünkü buna ihtiyaçları yok!

Buradan, geri kalanı tasarımınıza uyacak şekilde ayarlıyor.


Vaov! Bunu nasıl buldunuz?: p Yarın sabah yönteminizi test edeceğim ve bence işe yarayacak, bu mehod'u test ettikten sonra daha fazla geri bildirim sağlayacağım. Böyle bir cevap için çok teşekkür ederim.
Daniyal Azram

4
İstatistik! Bir oyun tasarımcısı veya programcı ya üzere, istatistikler çok değer öğrenme. En azından, bir olasılık anlayışı (ve bunların nasıl birleştirileceği) son derece yararlıdır.
ACEfanatic02

1
Aynı şeyi önermek için gel. Mükemmel cevap. Ayrıca, bunun gibi bir çözümün zorluk seviyelerini tanıtmanın bir yolu olabileceğini unutmayın. Kolay = 0.5, orta = 0.25, sert = 0.10. vb.
Tasos

Bunun rastgele olmadığını kabul etmiyorum. Bu rastgele, sadece parçalı bir dağılım, genellikle tekdüze dağılımı düşünüyoruz. Ve senin fikrini eklemek için sadece "Kelimede rastgele bir harf seç" den daha ileri giderdim. Bunu en çok meydana gelen harflerle dağıtırdım. Örneğin "mississippi" daha fazla s ihtiyacı var ve ben onlardan daha fazla seçin.
Blaine


21

Tüm harflerinizin olasılığını, kelimelerinizin bulunduğu dilde oluşma sıklığına göre ağırlıklandırabilirsiniz. İyi bir kılavuz, scrabble setidir . Örneğin, İngilizce versiyonunda 12 E vardır ancak sadece bir Z ve bir Q vardır.

Bunu uygulamanın basit bir yolu, her harfin istendiği sıklıkta görünmesi ve ardından RNG'nizin rastgele bir konumdan bir harf almasını sağlamak için tüm harfleri ardışık bir dizeye koymaktır. Sözde kod örneği:

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

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

2
+1 Bu iyi bir kavram, ancak daha zarif bir uygulama olduğundan şüpheleniyorum.
Evorlor


Daha hassas bir dağıtım için, 1'e eşit olacak şekilde ölçeklendirilmiş bir harf frekansları tablosu depolayabilir , 0 ile 1 arasında rastgele bir sayı oluşturabilir ve her harfin frekansını rastgele sayıdan rastgele sayıya kadar çıkaran tablo üzerinde döngüye alabilirsiniz. sıfır veya negatif olur. Bunu, tablodaki en yaygın harfleri sıralayarak bile optimize edebilirsiniz. Ya da tablonun üzerinde tamamen döngü oluşturmamak için takma ad yöntemi gibi bir şey kullanın .
Ilmari Karonen

4
Bu sorunu çözmez. Sorun, kullanıcının oyunu bitirmek için belirli harflere ihtiyacı olmasıdır . Z'ye ihtiyaçları olduğunu mu söylüyorsun? Sonra ne? Bu, kullanıcının daha da sinirli olmasını sağlamak için nadir harfleri zorlaştırır.
AmazingDreams

@AmazingDreams iyi bir şeye işaret ediyor, ancak biraz değiştirebiliriz, böylece gerekli alfabelere daha fazla ağırlık ve başkalarına daha az ağırlık atayacağım. Bunu takip etmek için çok iyi bir kavram olduğunu söylemeliyim.
Daniyal Azram

4

Burada, değiştirebileceğiniz tek bir parametre kullanarak onu geliştirmenin bir yolu var k.

Sadece rastgele bir mektup seçmek yerine:

  1. rastgele bir mektup seç A
  2. rastgele bir sayı seç X
  3. eğer X > k ve A değil de [list of remaining needed letters], 1 de tekrar deneyin.

Ne kadar küçükse k, son harf daha çok gerekli olan harf Ao kadar sık olacaktır.

Algoritmayı değiştirmek için herhangi bir değerle oynayın k, örn k = 0.5 . Oyunun çok zor olduğunu düşünüyorsanız, 0.4makul bir değer bulana kadar yerine deneyin . Bu aynı zamanda doğrudan size bir zorluk ayarı verir , örneğin oyuncu oyunda ilerledikçe artırmak isteyebilirsiniz.


Cevabınız için teşekkürler ama bu ACEfanatic02'nin cevabı gibi görünüyor.
Daniyal Azram

3

Belirli bir süre içinde gerekli harflerin görünmesini sağlamanın basit bir yolu, bir diziyi kelimedeki harflerle ve alfabenin geri kalanıyla (belki de tekrarlanan) doldurmak, sonra diziyi rastgele karıştırmaktır (c ++ std :: random_shuffle Standart kütüphanede, farklı bir dil kullanıyorsanız uygulanması zor değildir).

Sözcükteki harflerin daha hızlı görünmesini istiyorsanız diziye sözcük harflerinin daha fazla kopyasını ekleyin.


0

C ++ kullanıyorsanız, zaten var olan bir dağıtımı kullanabilirsiniz http://en.cppreference.com/w/cpp/numeric/random/piecewise_constant_distribution

Ayrıca saf yöntemlerden daha iyi olan amortisman sabit zaman karmaşıklığına sahiptir. misal:

#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';
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.