D Programlama Dili - Çözümler

Yapılar

  1. Aksine bir neden olmadığı için, en basit olarak iki tane karakter ile:
    struct OyunKağıdı {
        dchar renk;
        dchar değer;
    }
    
  2. Yine çok basit olarak, yapı nesnesinin üyelerini yan yana çıkışa göndermek yeterli olur:
    void oyunKağıdıYazdır(OyunKağıdı kağıt) {
        write(kağıt.renk, kağıt.değer);
    }
    
  3. Eğer yeniSeri isminde başka bir işlevin yazılmış olduğunu kabul edersek, yeniDeste işlevini de onu her renk için dört kere çağırarak kolayca yazabiliriz:
    OyunKağıdı[] yeniDeste()
    out (sonuç) {
        assert(sonuç.length == 52);
    
    } do {
        OyunKağıdı[] deste;
    
        deste ~= yeniSeri('♠');
        deste ~= yeniSeri('♡');
        deste ~= yeniSeri('♢');
        deste ~= yeniSeri('♣');
    
        return deste;
    }
    

    İşin diğer bölümü yararlandığımız yeniSeri tarafından halledilir. Bu işlev verilen renk bilgisini bir dizginin bütün elemanlarıyla sırayla birleştirerek bir seri oluşturuyor:

    OyunKağıdı[] yeniSeri(dchar renk)
    in {
        assert((renk == '♠') ||
               (renk == '♡') ||
               (renk == '♢') ||
               (renk == '♣'));
    
    } out (sonuç) {
        assert(sonuç.length == 13);
    
    } do {
        OyunKağıdı[] seri;
    
        foreach (değer; "234567890JQKA") {
            seri ~= OyunKağıdı(renk, değer);
        }
    
        return seri;
    }
    

    Program hatalarını önlemek için işlevlerin giriş koşullarını ve çıkış garantilerini de yazdığıma dikkat edin.

  4. Rasgele seçilen iki elemanı değiş tokuş etmek, sonuçta destenin karışmasını da sağlar. Rastgele seçim sırasında, küçük de olsa aynı elemanı seçme olasılığı da vardır. Ama bu önemli bir sorun oluşturmaz, çünkü elemanı kendisiyle değiştirmenin etkisi yoktur.
    void karıştır(OyunKağıdı[] deste, int değişTokuşAdedi) {
        /* Not: Daha etkin bir yöntem, desteyi başından sonuna
         *      kadar ilerlemek ve her elemanı destenin sonuna
         *      doğru rasgele bir elemanla değiştirmektir.
         *
         * En doğrusu, zaten aynı algoritmayı uygulayan
         * std.algorithm.randomShuffle işlevini çağırmaktır. Bu
         * karıştır() işlevini bütünüyle kaldırıp main() içinde
         * açıklandığı gibi randomShuffle()'ı çağırmak daha doğru
         * olur. */
        foreach (i; 0 .. değişTokuşAdedi) {
    
            // Rasgele iki tanesini seç
            immutable birinci = uniform(0, deste.length);
            immutable ikinci = uniform(0, deste.length);
    
            // Değiş tokuş et
            swap(deste[birinci], deste[ikinci]);
        }
    }
    

    O işlevde std.algorithm modülündeki swap işlevinden yararlandım. swap, kendisine verilen iki değeri değiş tokuş eder. Temelde şu işlev gibi çalışır:

    void değişTokuş(ref OyunKağıdı soldaki,
                    ref OyunKağıdı sağdaki) {
        immutable geçici = soldaki;
        soldaki = sağdaki;
        sağdaki = geçici;
    }
    

Programın tamamı şöyle:

import std.stdio;
import std.random;
import std.algorithm;

struct OyunKağıdı {
    dchar renk;
    dchar değer;
}

void oyunKağıdıYazdır(OyunKağıdı kağıt) {
    write(kağıt.renk, kağıt.değer);
}

OyunKağıdı[] yeniSeri(dchar renk)
in {
    assert((renk == '♠') ||
           (renk == '♡') ||
           (renk == '♢') ||
           (renk == '♣'));

} out (sonuç) {
    assert(sonuç.length == 13);

} do {
    OyunKağıdı[] seri;

    foreach (değer; "234567890JQKA") {
        seri ~= OyunKağıdı(renk, değer);
    }

    return seri;
}

OyunKağıdı[] yeniDeste()
out (sonuç) {
    assert(sonuç.length == 52);

} do {
    OyunKağıdı[] deste;

    deste ~= yeniSeri('♠');
    deste ~= yeniSeri('♡');
    deste ~= yeniSeri('♢');
    deste ~= yeniSeri('♣');

    return deste;
}

void karıştır(OyunKağıdı[] deste, int değişTokuşAdedi) {
    /* Not: Daha etkin bir yöntem, desteyi başından sonuna
     *      kadar ilerlemek ve her elemanı destenin sonuna
     *      doğru rasgele bir elemanla değiştirmektir.
     *
     * En doğrusu, zaten aynı algoritmayı uygulayan
     * std.algorithm.randomShuffle işlevini çağırmaktır. Bu
     * karıştır() işlevini bütünüyle kaldırıp main() içinde
     * açıklandığı gibi randomShuffle()'ı çağırmak daha doğru
     * olur. */
    foreach (i; 0 .. değişTokuşAdedi) {

        // Rasgele iki tanesini seç
        immutable birinci = uniform(0, deste.length);
        immutable ikinci = uniform(0, deste.length);

        // Değiş tokuş et
        swap(deste[birinci], deste[ikinci]);
    }
}

void main() {
    OyunKağıdı[] deste = yeniDeste();

    karıştır(deste, 100);
    /* Not: Yukarıdaki karıştır() çağrısı yerine aşağıdaki
     *      randomShuffle() daha doğru olur:
     *
     * randomShuffle(deste);
     */
    foreach (kağıt; deste) {
        oyunKağıdıYazdır(kağıt);
        write(' ');
    }

    writeln();
}