Günün Rastgele Golf # 6: Bir d20 yuvarlayın


17

Seri Hakkında

Öncelikle, bunu diğer kod golf zorlukları gibi ele alabilir ve seri hakkında endişelenmeden cevaplayabilirsiniz. Ancak, tüm zorluklarda bir lider tablosu vardır. Liderlik tablosunu, diziyle ilgili daha fazla bilgiyi ilk gönderide bulabilirsiniz .

Dizi için sıralanmış bir sürü fikrim olmasına rağmen, gelecekteki zorluklar henüz çözülmedi. Herhangi bir öneriniz varsa, lütfen ilgili sandbox gönderisinde bana bildirin .

Delik 6: D20 yuvarlayın

Masa üstü RPG'lerde çok yaygın bir kalıp yirmi taraflı kalıptır ( genellikle d20 olarak bilinen bir ikosahedron ). Böyle bir ölümü yuvarlamak senin görevin. Ancak, sadece 1 ile 20 arasında rastgele bir sayı döndürüyorsanız, bu biraz önemsiz olurdu. Yani göreviniz belirli bir kalıp için rastgele bir ağ oluşturmaktır.

Aşağıdaki ağı kullanacağız:

resim açıklamasını buraya girin

Bu bir üçgen şerittir, bu yüzden tamsayıların bir listesi olarak kolayca temsil edilebilir. Örneğin, size giriş verilirse:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Bu şu ölüme karşılık gelir (eğlenceli gerçek: bu Magic tarafından kullanılan nettir : Toplama yaşam sayaçları / spin-down zar).

resim açıklamasını buraya girin

Ancak, bu ölümü temsil eden tek ağ bu değildir. Yüzleri nasıl açtığımıza bağlı olarak, 60 farklı ağ var. İşte iki tane daha:

[1, 8, 9, 10, 2, 3, 4, 5, 6, 7, 17, 18, 19, 11, 12, 13, 14, 15, 16, 20]
[10, 9, 18, 19, 11, 12, 3, 2, 1, 8, 7, 17, 16, 20, 13, 14, 4, 5, 6, 15]

Veya grafiksel olarak (basitlik için yüz etiketlerini döndürmedim):

resim açıklamasını buraya girin resim açıklamasını buraya girin

Meydan okuma

Bir kalıbı temsil eden bir tam sayı listesi (yukarıda açıklandığı gibi) ve bir tam sayı N, çıktıN , bağımsız bir şekilde, eşit olarak rasgele d20 ağları verilen kalıbın karşılık gelir. (Yani, olası 60 ağın her biri aynı üretilme olasılığına sahip olmalıdır.)

Tabii ki, PRNG'lerin teknik sınırlamaları nedeniyle, mükemmel tekdüzelik imkansız olacaktır. Gönderinizin tekdüzeliğini değerlendirmek amacıyla, aşağıdaki işlemler mükemmel şekilde eşit dağılımlar sağladığı düşünülecektir:

  • Bir PRNG'den (herhangi bir aralıkta) bir sayı elde edilmesi (yaklaşık olarak) tek tiptir.
  • Modulo veya çarpma (veya değerleri eşit olarak dağıtan başka bir işlem) aracılığıyla daha büyük bir sayı kümesi üzerinde daha küçük bir kümeye tekdüze bir dağılım eşleme. Daha büyük kümenin, küçük kümenin en az 1024 katı değerinden fazla değer içermesi gerekir.

Bu varsayımlar göz önüne alındığında, algoritmanız mükemmel bir şekilde eşit dağılım sağlamalıdır.

Programınız bir saniyeden daha kısa sürede 100 ağ üretebilmelidir (bu nedenle, yukarıda verilen kalıba karşılık gelene kadar rastgele ağlar oluşturmayı denemeyin).

STDIN (veya en yakın alternatif), komut satırı bağımsız değişkeni veya işlev bağımsız değişkeni ile girdi alarak ve sonucu STDOUT (veya en yakın alternatif), işlev dönüş değeri veya işlev (çıkış) parametresi aracılığıyla çıktı alarak bir program veya işlev yazabilirsiniz.

Giriş ve çıkış herhangi bir uygun, açık, düz liste biçiminde olabilir. D20'nin yüz değerlerinin, dilinizin doğal tamsayı tipine uyan farklı, pozitif tamsayı olduğunu varsayabilirsiniz.

Bu kod golf, yani en kısa gönderme (bayt cinsinden) kazanır. Ve elbette, kullanıcı başına en kısa gönderim de serinin genel skor tablosuna girecektir.

Örnek Çıktılar

Giriş için

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Belirli bir sırayla (olası bir hata yapmadım) 60 olası ağlar şunlardır:

[11, 10, 9, 18, 19, 20, 13, 12, 3, 2, 1, 8, 7, 17, 16, 15, 14, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[8, 7, 17, 18, 9, 10, 2, 1, 5, 6, 15, 16, 20, 19, 11, 12, 3, 4, 14, 13]
[3, 12, 13, 14, 4, 5, 1, 2, 10, 11, 19, 20, 16, 15, 6, 7, 8, 9, 18, 17]
[3, 4, 5, 1, 2, 10, 11, 12, 13, 14, 15, 6, 7, 8, 9, 18, 19, 20, 16, 17]
[11, 19, 20, 13, 12, 3, 2, 10, 9, 18, 17, 16, 15, 14, 4, 5, 1, 8, 7, 6]
[4, 14, 15, 6, 5, 1, 2, 3, 12, 13, 20, 16, 17, 7, 8, 9, 10, 11, 19, 18]
[2, 10, 11, 12, 3, 4, 5, 1, 8, 9, 18, 19, 20, 13, 14, 15, 6, 7, 17, 16]
[4, 5, 1, 2, 3, 12, 13, 14, 15, 6, 7, 8, 9, 10, 11, 19, 20, 16, 17, 18]
[10, 2, 1, 8, 9, 18, 19, 11, 12, 3, 4, 5, 6, 7, 17, 16, 20, 13, 14, 15]
[3, 2, 10, 11, 12, 13, 14, 4, 5, 1, 8, 9, 18, 19, 20, 16, 15, 6, 7, 17]
[7, 8, 1, 5, 6, 15, 16, 17, 18, 9, 10, 2, 3, 4, 14, 13, 20, 19, 11, 12]
[13, 12, 11, 19, 20, 16, 15, 14, 4, 3, 2, 10, 9, 18, 17, 7, 6, 5, 1, 8]
[16, 15, 14, 13, 20, 19, 18, 17, 7, 6, 5, 4, 3, 12, 11, 10, 9, 8, 1, 2]
[15, 16, 17, 7, 6, 5, 4, 14, 13, 20, 19, 18, 9, 8, 1, 2, 3, 12, 11, 10]
[20, 13, 12, 11, 19, 18, 17, 16, 15, 14, 4, 3, 2, 10, 9, 8, 7, 6, 5, 1]
[5, 4, 14, 15, 6, 7, 8, 1, 2, 3, 12, 13, 20, 16, 17, 18, 9, 10, 11, 19]
[10, 11, 12, 3, 2, 1, 8, 9, 18, 19, 20, 13, 14, 4, 5, 6, 7, 17, 16, 15]
[4, 3, 12, 13, 14, 15, 6, 5, 1, 2, 10, 11, 19, 20, 16, 17, 7, 8, 9, 18]
[19, 20, 13, 12, 11, 10, 9, 18, 17, 16, 15, 14, 4, 3, 2, 1, 8, 7, 6, 5]
[1, 8, 9, 10, 2, 3, 4, 5, 6, 7, 17, 18, 19, 11, 12, 13, 14, 15, 16, 20]
[8, 1, 5, 6, 7, 17, 18, 9, 10, 2, 3, 4, 14, 15, 16, 20, 19, 11, 12, 13]
[18, 9, 8, 7, 17, 16, 20, 19, 11, 10, 2, 1, 5, 6, 15, 14, 13, 12, 3, 4]
[12, 3, 2, 10, 11, 19, 20, 13, 14, 4, 5, 1, 8, 9, 18, 17, 16, 15, 6, 7]
[2, 3, 4, 5, 1, 8, 9, 10, 11, 12, 13, 14, 15, 6, 7, 17, 18, 19, 20, 16]
[10, 9, 18, 19, 11, 12, 3, 2, 1, 8, 7, 17, 16, 20, 13, 14, 4, 5, 6, 15]
[9, 8, 7, 17, 18, 19, 11, 10, 2, 1, 5, 6, 15, 16, 20, 13, 12, 3, 4, 14]
[16, 17, 7, 6, 15, 14, 13, 20, 19, 18, 9, 8, 1, 5, 4, 3, 12, 11, 10, 2]
[17, 7, 6, 15, 16, 20, 19, 18, 9, 8, 1, 5, 4, 14, 13, 12, 11, 10, 2, 3]
[1, 5, 6, 7, 8, 9, 10, 2, 3, 4, 14, 15, 16, 17, 18, 19, 11, 12, 13, 20]
[9, 18, 19, 11, 10, 2, 1, 8, 7, 17, 16, 20, 13, 12, 3, 4, 5, 6, 15, 14]
[16, 20, 19, 18, 17, 7, 6, 15, 14, 13, 12, 11, 10, 9, 8, 1, 5, 4, 3, 2]
[5, 1, 2, 3, 4, 14, 15, 6, 7, 8, 9, 10, 11, 12, 13, 20, 16, 17, 18, 19]
[8, 9, 10, 2, 1, 5, 6, 7, 17, 18, 19, 11, 12, 3, 4, 14, 15, 16, 20, 13]
[13, 20, 16, 15, 14, 4, 3, 12, 11, 19, 18, 17, 7, 6, 5, 1, 2, 10, 9, 8]
[6, 15, 16, 17, 7, 8, 1, 5, 4, 14, 13, 20, 19, 18, 9, 10, 2, 3, 12, 11]
[6, 5, 4, 14, 15, 16, 17, 7, 8, 1, 2, 3, 12, 13, 20, 19, 18, 9, 10, 11]
[7, 6, 15, 16, 17, 18, 9, 8, 1, 5, 4, 14, 13, 20, 19, 11, 10, 2, 3, 12]
[19, 18, 17, 16, 20, 13, 12, 11, 10, 9, 8, 7, 6, 15, 14, 4, 3, 2, 1, 5]
[14, 15, 6, 5, 4, 3, 12, 13, 20, 16, 17, 7, 8, 1, 2, 10, 11, 19, 18, 9]
[17, 18, 9, 8, 7, 6, 15, 16, 20, 19, 11, 10, 2, 1, 5, 4, 14, 13, 12, 3]
[6, 7, 8, 1, 5, 4, 14, 15, 16, 17, 18, 9, 10, 2, 3, 12, 13, 20, 19, 11]
[14, 13, 20, 16, 15, 6, 5, 4, 3, 12, 11, 19, 18, 17, 7, 8, 1, 2, 10, 9]
[20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[7, 17, 18, 9, 8, 1, 5, 6, 15, 16, 20, 19, 11, 10, 2, 3, 4, 14, 13, 12]
[15, 6, 5, 4, 14, 13, 20, 16, 17, 7, 8, 1, 2, 3, 12, 11, 19, 18, 9, 10]
[9, 10, 2, 1, 8, 7, 17, 18, 19, 11, 12, 3, 4, 5, 6, 15, 16, 20, 13, 14]
[2, 1, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7, 17, 18, 19, 20, 13, 14, 15, 16]
[12, 13, 14, 4, 3, 2, 10, 11, 19, 20, 16, 15, 6, 5, 1, 8, 9, 18, 17, 7]
[17, 16, 20, 19, 18, 9, 8, 7, 6, 15, 14, 13, 12, 11, 10, 2, 1, 5, 4, 3]
[18, 17, 16, 20, 19, 11, 10, 9, 8, 7, 6, 15, 14, 13, 12, 3, 2, 1, 5, 4]
[18, 19, 11, 10, 9, 8, 7, 17, 16, 20, 13, 12, 3, 2, 1, 5, 6, 15, 14, 4]
[11, 12, 3, 2, 10, 9, 18, 19, 20, 13, 14, 4, 5, 1, 8, 7, 17, 16, 15, 6]
[15, 14, 13, 20, 16, 17, 7, 6, 5, 4, 3, 12, 11, 19, 18, 9, 8, 1, 2, 10]
[19, 11, 10, 9, 18, 17, 16, 20, 13, 12, 3, 2, 1, 8, 7, 6, 15, 14, 4, 5]
[12, 11, 19, 20, 13, 14, 4, 3, 2, 10, 9, 18, 17, 16, 15, 6, 5, 1, 8, 7]
[20, 16, 15, 14, 13, 12, 11, 19, 18, 17, 7, 6, 5, 4, 3, 2, 10, 9, 8, 1]
[13, 14, 4, 3, 12, 11, 19, 20, 16, 15, 6, 5, 1, 2, 10, 9, 18, 17, 7, 8]
[5, 6, 7, 8, 1, 2, 3, 4, 14, 15, 16, 17, 18, 9, 10, 11, 12, 13, 20, 19]
[14, 4, 3, 12, 13, 20, 16, 15, 6, 5, 1, 2, 10, 11, 19, 18, 17, 7, 8, 9]

Diğer herhangi bir ağ için, girişlerin her birinde girişteki th sayısı iile değiştirin i(buradai 1 tabanlı).

İlgili Zorluklar

Liderler Sıralaması

Serinin ilk yazısı bir skor tablosu oluşturur.

Yanıtlarınızın göründüğünden emin olmak için lütfen aşağıdaki Markdown şablonunu kullanarak her cevaba bir başlık ile başlayın:

## Language Name, N bytes

Ngönderiminizin büyüklüğü nerede . Puanınızı artırmak varsa, olabilir onları içinden vurarak, başlığa eski hesapları tutmak. Örneğin:

## Ruby, <s>104</s> <s>101</s> 96 bytes

(Dil şu anda gösterilmiyor, ancak snippet gerektiriyor ve ayrıştırıyor ve gelecekte bir dil lider tablosu ekleyebilirim.)


Tartışmamızla ilgili olarak, daha net hale getirmek için "zorunluluk" kelimesini ekledim. Sanırım bundan yararlandığım boşlukları kapatıyor. Yine de, kullandığım yaklaşımın (geçersiz olsa da) ilginç olduğunu düşünüyorum.
Level River St

Bu neredeyse sandbox yazıma benziyor!
Rɪᴋᴇʀ

@RikerW Sandbox yaparken bunu düşündüm. ;) (O zaman benimki doğrudan senin altındaydı. Bunun sana ilham verdiğini sanıyordum.) Seninki açıkçası çok daha basit (muhtemelen iyi bir şey).
Martin Ender

Seninkini hiç görmedim. Bu garip, sanırım ilk sayfadakilerin hepsini okudum. Ama hayır, bağımsız olarak benimkini yaptım.
Rɪᴋᴇʀ

"Bir d20 açın" başlıklı değil mi?
Titus

Yanıtlar:


7

Yakut, 160 bayt (rev B)

Martin Büttner'ın önerileri sayesinde 17 bayt tasarruf edildi.

->a,n{n.times{k=rand 60
%w{ABCD@GHIJKLMNEFPQRSO PFENOSRQHG@DCMLKJIAB GFPQHIA@DENOSRJKBCML}.map{|b|k.times{a=b.chars.map{|i|a[i.ord-64]}}}
k>29&&a.reverse!
p a}}

Yakut, 177 bayt (rev A)

->n,a{n.times{k=rand(60)
h=->b{k.times{|j|a=(0..19).map{|i|a[b[i].ord-64]}}}
h['ABCD@GHIJKLMNEFPQRSO']
h['PFENOSRQHG@DCMLKJIAB']
h['GFPQHIA@DENOSRJKBCML']
k>29&&a.reverse!
p a}}

açıklama

Mümkün olan tüm yönelimleri bir yüz (3 kat), bir tepe (5 kat) ve iki kenar (2 kat) etrafında döndürerek oluşturmak mümkündür. Ama sadece herhangi bir yüz ve kenar değil. Eksenler doğru ilişkiye sahip olmalı ve dönüşler doğru sırayla yapılmalıdır, aksi takdirde garip şeyler olabilir.

Ben bunu yaptım (Martin'in bunu farklı yaptığını anlasam da).

Bir tetrahedronun tüm yönelimleri, aşağıdaki üç simetri işleminin kombinasyonları ile üretilebilir:

a) Kenarların orta noktalarından sağda iki adet iki katlı eksen etrafında dönme (bunlar birbirine dik açılıdır. Eğer bunları çarparsak, kalan kenar çifti boyunca üçüncü bir 2 katlı ekseni keşfederiz.)

b) Bir tepe noktasından ve bir yüzeyden geçen 2 katlı eksenlere çapraz 3 katlı bir eksen etrafında dönme.

İkosahedronun simetrisi, tetrahedronunkinin bir üst kümesidir. Aşağıdaki resimde https://en.wikipedia.org/wiki/Icosahedron adresinden , sarı yüzler ve kırmızı yüzler iki farklı tetrahedra (veya alternatif olarak tek bir oktahedron) tanımlarken, iki mavi yüz için ortak kenarlar üç çifttir. dik açılar (ve bir küpün yüzlerinde uzanır.)

İkosahedronun tüm oryantasyonları, yukarıda belirtilen simetri operasyonları ve ilave 5 kat operasyon ile üretilebilir.

resim açıklamasını buraya girin

Yukarıda belirtilen dört eksenden üçüne yakın dönüşler, ''işaretler arasındaki sihirli tellerle temsil edilir . İkinci 2 kat ekseni etrafındaki döndürme farklıdır ve sadece diziyi ters çevirerek yapılabilir a[].

Test programında yönlendirilmemiş:

f=->a,n{
  n.times{                     #Iterate n times, using the result from the previous iteration to generate the next
    k=rand(60)                 #pick a random number

    h=->b{                     #helper function taking a string representing a transformation
      k.times{|j|              #which is performed on a using the number of times according to k
        a=(0..19).map{|i|a[b[i].ord-64]}
      }
    }

    #Rotate about axes k times (one 5-fold, one 3-fold, two 2-fold)
    #The first three axes have coprime rotation orders
    #And the rotations themselves take care of the modulus operation so no need to add it.
    #The second 2-fold rotation is equivalent to reversing the order
    #And is applied to the last 30 numbers as it is not coprime with the first 2-fold rotation.

    h['ABCD@GHIJKLMNEFPQRSO']  #rotate k times about 5-fold axis
    h['PFENOSRQHG@DCMLKJIAB']  #rotate k times about 3-fold axis
    h['GFPQHIA@DENOSRJKBCML']  #rotate k times about 2-fold axis
    k>29&&a.reverse!
    p a
  }
}

z=(1..20).map{|i|i} 
f[z,50]

Alternatif çözüm 131 bayt (İkili rasgele yürüme yaklaşımı nedeniyle geçersiz, sadece yaklaşık doğru dağıtım verir.)

->a,n{(n*99).times{|i|s=['@DEFGHIABCMNOPQRJKLS','ABCD@GHIJKLMNEFPQRSO'][rand(2)] 
a=(0..19).map{|i|a[s[i].ord-64]}
i%99==98&&p(a)}}

Bu bir karışıklıktır (rubik küpünü karıştırmak için kullanılan programlar gibi).

Kullandığım spesifik rotasyonlar en belirgin iki rotasyon:

120 derece döndürme (ilk diyagram başına yaklaşık 1 ve 20 yüzler)

-72 derece dönme (ilk diyagram başına 1,2,3,4,5 ve 16,17,18,19,20'de ortak olan köşeler hakkında.)

parayı 99 kez çeviriyoruz ve her seferinde kafa veya kuyruk olmasına bağlı olarak bu iki rotasyondan birini gerçekleştiriyoruz.

Bu deterministik olarak değiştirmenin oldukça kısa sekanslara yol açtığını unutmayın. Örneğin, doğru dönme duyularıyla, sadece 2 periyotla 180 derecelik bir dönüş üretilebilir.


Bir operasyon seçmek için bozuk para çevirmek, binom dağılımına tekdüze bir dağılımdan daha yakın bir şey verecektir.
Sparr

@Sparr durum alanı rastgele yürüyüşten daha büyük olsaydı durum böyle olurdu. Ancak bu durumda, sadece 6 adımlık rastgele bir yürüyüş 2 ^ 6 = 64 olasılık kadar açılabilir (onları saymadım) ve durum alanımız sadece 60'tır. 99 adımdan sonra (2 ^ 99 farklı yol) her şey en azından sayıları oluşturmak için kullanılan PRNG'nin tek bir örneği kadar eşit olarak dağıtılmalıdır.
Level River St

@ MartinBüttner İpuçları için teşekkürler, işe yarayanları uyguladım. b.mapdoğrudan çalışmıyor, çalışması gerekiyor b.chars.map(Ruby 1.9.3'e sahip olduğum için makinemde çalışmayan BTW, ancak Ideone üzerinde çalışıyor.) Bu adil bir tasarruf. Çalışacak kaydetmek için yazdırılamaz karakterler için sihirli dizeleri değiştirmeyi düşünmüyorum -64: %w{}yorumladı \n(yanı sıra boşluk) oluşturulan dizede dizeler arasında bir ayırıcı olarak. Diğer yazdırılamaz ASCII karakterleriyle ne yapacağına dair hiçbir fikrim yok.
Level River St

@Martin bu beklediğimden daha zordu - ilk başta kodum düzgün çalışmadığında şaşırdım, sonra bir mola verdim ve aniden 2 kat ve 3 kat simetrilerin aynı karşılıklı ilişkiye sahip olması gerektiğini anladım bir tetrahedron üzerinde (Farklı bir üçgen yüz için döndüğüm üçgen yüzünü değiştirmek zorunda kaldım.)
Level River St

1
Yeni kilidi açılan geometri rozetiyle ilk kullanıcı olduğunuzu tebrik ediyoruz. :)
Martin Ender

2

IA-32 makine kodu, 118 bayt

HexDump:

60 33 c0 51 8b 74 24 28 8b fa 6a 05 59 f3 a5 e8
21 00 00 00 20 c4 61 cd 6a 33 00 84 80 ad a8 33
32 00 46 20 44 8e 48 61 2d 2c 33 32 4a 00 21 20
a7 a2 90 8c 00 5b b1 04 51 0f c7 f1 83 e1 1f 49
7e f7 51 8b f2 56 8d 7c 24 e0 b1 14 f3 a4 5f 8b
f3 ac 8b ee d4 20 86 cc e3 0a 56 8d 74 04 e0 f3
a4 5e eb ed 59 e2 db 8b dd 59 e2 cc 59 83 c2 14
e2 91 61 c2 04 00

Biraz uzun, bu yüzden bazı açıklamalar önce gidiyor. Level River St'nin mevcut cevabı ile hemen hemen aynı algoritmayı kullandım . Cevabımı farklı kılmak için, sezgisel geometrik anlamı olması gerekmeyen, ancak bir şekilde daha uygun olan diğer temel permütasyonları aldım.

Kod temel olarak aşağıdakilerin sıralı bir uygulaması olan bir permütasyon üretmelidir:

  1. Aradığım 3 numaralı bir permütasyon p30 ... 2 kez uygulandı
  2. Aradığım 2 numaralı siparişin permütasyonu q20 veya 1 kez uygulandı
  3. Aradığım 5 numaralı bir permütasyon p50 ... 4 kez uygulandı
  4. Aradığım 2 numaralı başka bir permütasyon p20 veya 1 kez uygulandı

Bu permütasyonlar için birçok olası seçenek vardır. Bunlardan biri şöyledir:

p3 = [0   4   5   6   7   8   9   1   2   3  13  14  15  16  17  18  10  11  12  19]
q2 = [4   5   6   7   0   1   2   3  13  14  15  16  17   8   9  10  11  12  19  18]
p5 = [6   7   0   4   5  14  15  16  17   8   9   1   2   3  13  12  19  18  10  11]
p2 = [1   0   7   8   9  10  11   2   3   4   5   6  16  17  18  19  12  13  14  15]

Bu seçim diğerlerinden daha iyidir çünkü buradaki permütasyonlar, çalışma uzunluğu kodlaması ile sıkıştırılabilen uzun sıralı indekslere sahiptir - 4 permütasyon için sadece 29 bayt.

Rastgele sayıların oluşturulmasını basitleştirmek için, hepsi için 1 ... 30 aralığında güçleri seçtim (her permütasyonun kaç kez uygulandığını). Bu, kodda çok fazla çalışmaya yol açar, çünkü örneğin p3her seferinde 3 kez çarpıldığı zaman bir kimlik permütasyonu olur. Bununla birlikte, kod bu şekilde daha küçüktür ve aralık 30'a bölünebildiği sürece, çıktının eşit dağılımı olacaktır.

Ayrıca, güçler pozitif olmalıdır, böylece çalışma uzunluğu kod çözme işlemi en az bir kez gerçekleştirilir.

Kodda 4 iç içe döngü vardır; taslak şöyle:

void doit(int n, uint8_t* output, const uint8_t input[20])
{    
    uint8_t temp[20];

    n_loop: for i_n = 0 ... n
    {
        memcpy(output, input, 20);
        expr_loop: for i_expr = 0 ... 3
        {
            power = rand(1 ... 30);
            power_loop: for i_power = 0 ... power
            {
                memcpy(temp, output, 20);
                output_index = 0;
                perm_loop: do while length > 0
                {
                    index = ...; // decode it
                    length = ...; // decode it
                    memcpy(output + output_index, temp + index, length);
                    output_index += length;
                }
            }
        }
        output += 20;
    }
}

Umarım bu sözde kod aşağıdaki satır içi montaj kodundan daha açıktır.

_declspec(naked) void __fastcall doit(int n, uint8_t* output, const uint8_t* input)
{
    _asm {
        pushad
        xor eax, eax

        n_loop:
            push ecx

            ; copy from input to output
            mov esi, [esp + 0x28]
            mov edi, edx
            push 5
            pop ecx
            rep movsd

            call end_of_data
#define rl(index, length) _emit(length * 32 + index)
            rl(0, 1)
            rl(4, 6)
            rl(1, 3)
            rl(13, 6)
            rl(10, 3)
            rl(19, 1)
            _emit(0)

            rl(4, 4)
            rl(0, 4)
            rl(13, 5)
            rl(8, 5)
            rl(19, 1)
            rl(18, 1)
            _emit(0)

            rl(6, 2)
            rl(0, 1)
            rl(4, 2)
            rl(14, 4)
            rl(8, 2)
            rl(1, 3)
            rl(13, 1)
            rl(12, 1)
            rl(19, 1)
            rl(18, 1)
            rl(10, 2)
            _emit(0)

            rl(1, 1)
            rl(0, 1)
            rl(7, 5)
            rl(2, 5)
            rl(16, 4)
            rl(12, 4)
            _emit(0)

            end_of_data:
            pop ebx ; load the address of the encoded data
            mov cl, 4

            expr_loop:
                push ecx

                make_rand:
                rdrand ecx
                and ecx, 31
                dec ecx
                jle make_rand

                ; input: ebx => encoding of permutation
                ; output: ebp => encoding of next permutation
                power_loop:
                    push ecx

                    ; copy from output to temp
                    mov esi, edx
                    push esi
                    lea edi, [esp - 0x20]
                    mov cl, 20
                    rep movsb
                    pop edi

                    ; ebx => encoding of permutation
                    ; edi => output
                    mov esi, ebx
                    perm_loop:
                        ; read a run-length
                        lodsb
                        mov ebp, esi

                        _emit(0xd4)             ; divide by 32, that is, split into
                        _emit(32)               ; index (al) and length (ah)
                        xchg cl, ah             ; set ecx = length; also makes eax = al
                        jecxz perm_loop_done    ; zero length => done decoding
                        push esi
                        lea esi, [esp + eax - 0x20]
                        rep movsb
                        pop esi
                        jmp perm_loop

                    perm_loop_done:
                    pop ecx
                    loop power_loop

                mov ebx, ebp
                pop ecx
                loop expr_loop

            pop ecx
            add edx, 20
            loop n_loop

        popad
        ret 4
    }
}

Bazı eğlenceli uygulama ayrıntıları:

  • Girintili montajı üst düzey dillerde kullandım; aksi halde kod anlaşılmaz bir karışıklık olurdu
  • Kodda depolanan verilere (kodlanmış permütasyonlar) erişmek callve kullanmak popiçin
  • jecxzTalimat elverişli beni sayı-uzunluk şifre prosesi için fesih olarak sıfır bayt kullanmanızı sağlar
  • Şans eseri, 30 sayısı (2 * 3 * 5) neredeyse 2'nin gücüdür. Bu, 1 ... 30 aralığında bir sayı oluşturmak için kısa kod kullanmama izin verir:

            and ecx, 31
            dec ecx
            jle make_rand
    
  • aamBir baytı bit alanlarına (3 bit uzunluk ve 5 bit dizin) ayırmak için "genel amaçlı bölme" komutunu ( ) kullanıyorum; şans, kod bu konumda cl = 0, bu yüzden her iki "taraf" yararlanırxchg

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.