Zar atarak oynanan oyunları merak edip "Going to Boston" diye bir oyun bulduk.
Her oyuncu için:
- Üç zar atın, en büyüğünü seçin (örnek: 2,5,1; seçilen: 5)
- İki zar atın, en büyüğünü seçin (örnek: 6,6; seçilen: 6)
- Tek zar atın, en büyüğünü seçin (örnek: 3; seçilen: 3)
- Hepsini toplayın; 5 + 6 + 3 = 14
Hangi oyuncunun toplamı daha büyükse o kazanır.
Hangi toplamdan büyük değerlerin kazanma şansının daha fazla olduğunu merak ettim. Hesaplayarak çözülebilmesine rağmen tembellik ettim ve bu oyunu deneyen bir program yazmaya karar verdim. İlk yazdığımda program yalnızca 20-30 satırdan ve yalnızca main() işlevinden oluşuyordu. Sonradan güzelleştirince ve açıklamalar ekleyince gereğinden fazla büyüdü. :/
Not: Hesaplama örneği olarak, toplam 3 gelmesi için ilk üç zarın hepsinin de 1 gelmesi, sonraki iki zarın ikisinin de 1 gelmesi ve son tek zarın da 1 gelmesi gerek. Böylece üç atışın da en büyüğü 1 oluyor ve toplam 3 ediyor. Bunun olasılığı, 6 zarın 1 gelme olasılığına eşit: 1/(6^^6) = 0.0000214335 = %0.0021 = yüz binde iki...
Birisinin ilgisini çekebilir diye buraya koymaya karar verdim.
Komut satırında belirtilen sayıda oyun oynatıyor ve hangi değerin kaç kere çıktığının histogramını gösteriyor:
'
$ ./deneme 100000
1: ⚁ ⚅ ⚃ = 12
2: ⚄ ⚄ ⚄ = 15
3: ⚁ ⚅ ⚀ = 9
4: ⚅ ⚃ ⚁ = 12
5: ⚃ ⚄ ⚂ = 12
6: ⚄ ⚅ ⚂ = 14
7: ⚄ ⚄ ⚄ = 15
8: ⚃ ⚄ ⚀ = 10
9: ⚅ ⚃ ⚂ = 13
10: ⚅ ⚄ ⚁ = 13
[...]
Değer Adet Yüzde YüzdeToplamı
3: 2 0.00% 0.00%
4: 31 0.03% 0.03%
5: 110 0.11% 0.14%
6: 375 0.38% 0.52% #
7: 1,069 1.07% 1.59% #####
8: 2,569 2.57% 4.16% #############
9: 4,820 4.82% 8.98% ########################
10: 7,762 7.76% 16.74% ########################################
11: 11,217 11.22% 27.95% #########################################################
12: 14,160 14.16% 42.11% ########################################################################
13: 15,520 15.52% 57.63% ################################################################################
14: 14,135 14.13% 71.77% ########################################################################
15: 12,022 12.02% 83.79% #############################################################
16: 8,769 8.77% 92.56% #############################################
17: 5,285 5.29% 97.85% ###########################
18: 2,154 2.15% 100.00% ###########
'
Anlaşılan, kazanma şansının büyük olması için 13'ten büyük değer yakalamak gerekiyor.
Program şöyle:
import std.range;
import std.algorithm;
import std.string;
import std.random;
import std.stdio;
import std.format;
import std.conv;
// "Going to Boston" oyununun kazanma olasılıklarını gösterir.
enum varsayılanDeneyAdedi = 10_000;
enum enKüçükZar = 1;
enum enBüyükZar = 6;
enum toplamZar = 3;
enum enKüçükSonuç = toplamZar * enKüçükZar;
enum enBüyükSonuç = toplamZar * enBüyükZar;
enum farklıSonuçAdedi = enBüyükSonuç - enKüçükSonuç + 1;
// Belirtilen sayıda zar atar ve en büyük olanını döndürür.
int atış(size_t adet)
in (adet >= 1)
out (sonuç; ((sonuç >= enKüçükZar) &&
(sonuç <= enBüyükZar)))
{
return iota(adet)
.map!(i => uniform(enKüçükZar, enBüyükZar + 1))
.array // <-- Buradaki .array, doğruluk açısından gerekli çünkü
// maxElement elemanları karşılaştırırken *aynı*
// eleman için uniform()'u dolaylı olarak birden
// fazla kere çağırmak zorunda kaldığından farklı
// değerler görebiliyor.
.maxElement;
}
// Bir el oynatır; yani, art arda üç, iki, ve tek zar atar. Her
// atıştaki en büyük değerden oluşan dizi döndürür.
int[] el()
// Not: Buradaki cast(), sonuç'un 'const'ını kaldırmak için
// gerekti. Çünkü, Phobos'un bir hatası olarak SortedRange.length
// const nesneler üzerinde derlenemiyor.
out (sonuç; (cast()sonuç).length == toplamZar)
{
return iota(toplamZar, 0, -1)
.map!(adet => atış(adet))
.array;
}
struct Sonuç {
size_t numara; // Deney numarası
int değer; // Elin değeri
string görüntü; // Elin görsel gösterimi
this(size_t indeks, int[] el) {
static const görüntüler = [ "⚀", "⚁", "⚂", "⚃", "⚄", "⚅" ];
this.numara = indeks + 1;
this.değer = el.sum;
this.görüntü = format!"%-( %s%)"(el.map!(zar => görüntüler[zar - 1]));
}
void toString(scope void delegate(const(char)[]) çıktı) {
formattedWrite(çıktı, "%7,s:%2s = %2s", numara, görüntü, değer);
}
}
// Belirtilen sayıda deney işletir ve sonuçlarını bir dizi olarak
// döndürür.
auto dene(size_t adet) {
return iota(adet)
.map!(i => Sonuç(i, el()))
.array;
}
// Histogramdaki eleman adedinin doğru olduğunu denetler.
bool uzunluğuDoğru(const size_t[int] histogram) {
return ((histogram.length >= 1) &&
(histogram.length <= farklıSonuçAdedi));
}
// Her el sonucundan kaç adet çıktığını sayar.
size_t[int] say(R)(R deneyler)
out (sonuç; ((deneyler.empty && sonuç.empty) ||
(!deneyler.empty && sonuç.uzunluğuDoğru)))
{
typeof(return) histogram;
deneyler
.map!(t => t.değer)
.each!(sonuç => histogram[sonuç]++);
return histogram;
}
void bilgiVer(const size_t[int] histogram)
in (histogram.uzunluğuDoğru)
{
const başlık = "Değer Adet Yüzde YüzdeToplamı";
writefln!"\n%s\n%s"(başlık, "-".replicate(başlık.walkLength));
const toplamDeney = histogram.byValue.sum;
const enBüyükAdet = histogram.byValue.maxElement;
double yüzdeToplamı = 0;
string bilgiSatırı(int sonuç) {
const yüzde = histogram[sonuç] / double(toplamDeney) * 100;
yüzdeToplamı += yüzde;
enum enBüyükÇubukUzunluğu = 80;
const uzunluk = histogram[sonuç] * enBüyükÇubukUzunluğu / enBüyükAdet;
const grafikÇubuğu = "#".replicate(uzunluk);
return format!"%2s:%9,s %6.2f%% %6.2f%% %s"(
sonuç, histogram[sonuç], yüzde, yüzdeToplamı, grafikÇubuğu);
}
writefln!"%-(%s\n%)"(histogram
.keys
.sort
.map!(sonuç => bilgiSatırı(sonuç)));
}
void main(string[] args) {
const adet = {
if (args.length == 1) {
writefln!"Deney adedi verilmedi; %,s varsayıyorum."(varsayılanDeneyAdedi);
return varsayılanDeneyAdedi;
} else {
return args[1].to!size_t;
}
}();
auto sonuçlar = dene(adet);
// Yalnızca ilk bir kaç deney sonucunu göstermekle yetiniyoruz
writefln!"%-(%s\n%)"(sonuçlar.take(10));
writeln("[...]");
const histogram = say(sonuçlar);
bilgiVer(histogram);
}
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]