デイ#6のランダムゴルフ:d20を転がす


17

シリーズについて

まず、これを他のコードゴルフチャレンジと同様に扱い、シリーズについてまったく心配することなく答えることができます。ただし、すべての課題にリーダーボードがあります。リーダーボードは、最初の投稿でシリーズに関する詳細情報とともに見つけることができます。

このシリーズにはたくさんのアイデアが並んでいますが、将来の課題はまだはっきりしていません。提案があれば、関連するサンドボックスの投稿でお知らせください。

穴6:d20を転がす

テーブルトップRPGで非常に一般的なダイスは、20面ダイス(20面体、一般にd20として知られています)です。このようなサイコロを振るのはあなたの仕事です。ただし、1〜20の間の乱数を返すだけの場合は、少し簡単です。だからあなたの仕事は、与えられたダイのランダムネットを生成することです。

次のネットを使用します。

ここに画像の説明を入力してください

これは三角形のストリップなので、整数のリストとして簡単に表すことができます。たとえば、入力が与えられた場合:

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

それは次のダイスに対応します(楽しい事実:これはマジックが使用するネットです:ライフカウンターの収集 /スピンダウンサイコロ)。

ここに画像の説明を入力してください

ただし、このダイを表すネットはこれだけではありません。顔の展開方法に応じて、60種類のネットがあります。さらに2つあります。

[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]

またはグラフィカルに(簡単にするために顔ラベルを回転させませんでした):

ここに画像の説明を入力してください ここに画像の説明を入力してください

チャレンジ

(上記の)ダイを表す整数のリストとintegerを指定すると、指定されたダイに対応する一様にランダムなd20ネットが独立してN出力さNれます。(つまり、60の可能なネットのそれぞれは、生成されるのと同じ確率を持つ必要があります。)

もちろん、PRNGの技術的な制限により、完全な均一性は不可能です。提出物の均一性を評価するために、次の操作は完全に均一な分布をもたらすと見なされます。

  • (ほぼ)均一であることが文書化されているPRNGから(任意の範囲で)数値を取得する。
  • モジュロまたは乗算(または値を均等に分散する他の演算)を介して、大きな数のセットにわたる均一な分布を小さなセットにマッピングします。大きいセットには、小さいセットの少なくとも1024倍の値を含める必要があります。

これらの仮定を考えると、アルゴリズムは完全に均一な分布を生成する必要があります。

プログラムは1秒以内に100個のネットを生成できる必要があります(したがって、上記のダイに対応するまでランダムネットを生成しないでください)。

プログラムまたは関数を作成し、STDIN(または最も近い代替)、コマンドライン引数または関数引数を介して入力を取得し、STDOUT(または最も近い代替)、関数の戻り値または関数(out)パラメーターを介して結果を出力できます。

入力および出力は、任意の便利で明確なフラットリスト形式にすることができます。d20の面の値は明確で正の整数であり、言語の自然な整数型に適合すると仮定できます。

これはコードゴルフであるため、最短の提出(バイト単位)が優先されます。そしてもちろん、ユーザーごとの最短投稿もシリーズの総合リーダーボードに入ります。

サンプル出力

入力用

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

60の可能なネット(私が間違えなかった場合)は、順不同です:

[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]

他のネットのため、単にのすべての出現置き換えるii(入力で番目数i1ベースである)を。

関連する課題

リーダーボード

シリーズの最初の投稿はリーダーボードを生成します。

回答が表示されるようにするには、次のマークダウンテンプレートを使用して、すべての回答を見出しで開始してください。

## Language Name, N bytes

N提出物のサイズはどこですか。スコアを改善する場合、古いスコアを打つことで見出しに残すことができます。例えば:

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

(言語は現在表示されていませんが、スニペットはそれを必要とし、解析します。将来、言語ごとのリーダーボードを追加するかもしれません。)


私たちの議論に関しては、明確にするために「必要」という言葉を追加しました。これは私が利用してきた抜け穴を塞ぐと思います。それでも、私は(無効ではあるが)私が使用したアプローチは興味深いと思います。
レベルリバーセント

これは私のサンドボックスの投稿とほぼ同じです!
Rɪᴋᴇʀ

@RikerWサンドボックス化したとき、私はそれを考えました。;)(当時、私のものはあなたのもののすぐ下にありました。これはあなたのものに影響を与えたと思います。)しかし、あなたのものは明らかにずっとシンプルです(おそらく良いことです)。
マーティンエンダー

あなたを見たことがありません。それは奇妙で、最初のページのすべてを読んだと思いました。しかし、いいえ、私は独立して私のものを作りました。
Rɪᴋᴇʀ

「unfold a d20」というタイトルを付けてはいけませんか?
タイタス

回答:


7

ルビー、160バイト(rev B)

MartinBüttnerからの提案により、17バイトが節約されました。

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

ルビー、177バイト(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}}

説明

1つの面(3つ折り)、1つの頂点(5つ折り)、2つのエッジ(2つ折り)を中心に回転することで、可能なすべての方向を生成できます。しかし、顔やエッジだけではありません。軸は正しい関係になければならず、回転は正しい順序で行わなければなりません。そうしないと、奇妙なことが起こります。

これが私がやった方法です(マーティンが別の方法でやったことは理解していますが)。

四面体のすべての方向は、次の3つの対称操作の組み合わせによって生成できます。

a)エッジの中点を通る2つの2軸の周りの回転(これらは互いに直角です。それらを互いに乗算すると、残りのエッジのペアを通る3番目の2軸が見つかります。)

b)頂点と面を通過する、2倍の軸に対角線上の3倍の軸を中心とした回転。

二十面体の対称性は、四面体の対称性のスーパーセットです。以下のhttps://en.wikipedia.org/wiki/Icosahedronの画像では、黄色の面と赤い面が2つの異なる四面体(または単一の八面体)を定義し、2つの青い面に共通するエッジは3つのペアにあります直角(および立方体の面上にあります。)

二十面体のすべての方向は、上記の対称操作と追加の5倍操作によって生成できます。

ここに画像の説明を入力してください

上記の4つの軸のうち3つについての回転は、''マーク間のマジックストリングで表されます。2番目の2軸の周りの回転は異なり、配列を逆にするだけで実行できますa[]

テストプログラムでゴルフをしていません:

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]

代替ソリューション131バイト(バイナリランダムウォークアプローチのため無効、おおよそ正しい分布しか得られません。)

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

これはスクランブルです(rubikのキューブをスクランブルするために使用されるプログラムによく似ています)。

私が使用する特定の回転は、最も明白な2つの回転です。

-120度の回転(最初の図の面1と20について)

-72度の回転(最初のダイアグラムごとに、1,2,3,4,5および16,17,18,19,20に共通の頂点について)

コインを99回裏返し、頭と尻のどちらであるかに応じて、これら2つの回転のいずれかを実行するたびに。

これらを決定論的に交互にすると、かなり短いシーケンスになることに注意してください。たとえば、正しい回転感覚で、ちょうど2の周期で180度の回転を生成できます。


コインをひっくり返して操作を選択すると、均一分布よりも二項分布に近いものが得られるようです。
スパー

状態空間がランダムウォークより大きい場合に発生する@Sparr。しかし、この場合、わずか6ステップのランダムウォークで最大2 ^ 6 = 64の可能性が開かれる可能性があり(数えていません)、状態空間は60だけです。99ステップ(2 ^ 99の異なるパス)の後すべては、数値の生成に使用されるPRNGの単一サンプルと少なくとも同じくらい均一に分布する必要があります。
レベルリバーセント

@MartinBüttnerヒントをありがとう、機能するものを適用しました。b.map直接動作しないb.chars.mapため、動作させる必要があります(Ruby 1.9.3があるため、マシンでは動作しませんが、Ideoneでは動作します)。印刷できない文字の魔法の文字列を変更して保存するの-64はうまくいかないと思います:%w{}\n生成された配列内の文字列間の区切り文字として(スペースだけでなく)解釈します。他の印刷不可能なASCII文字をどうするかはわかりません。
レベルリバーセント

@Martinこれは予想以上に難しかった-最初はコードが適切に機能しなかったときに困惑し、その後休憩して、突然2倍と3倍の対称性が同じ相互関係を持つ必要があることに気付いた四面体(別の三角形の面の周りに回転していた三角形の面を変更する必要がありました。)
レベル川St

1
新しくロック解除されたジオメトリバッジを初めてお使いになったことをおめでとうございます。:)
マーティンエンダー

2

IA-32マシンコード、118バイト

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

少し長いので、いくつかの説明を最初に行います。Level River Stの既存の回答とほぼ同じアルゴリズムを使用しました。答えを変えるために、他の基本的な順列を採用しました。これは必ずしも直感的な幾何学的意味を持っているわけではありませんが、何らかの形で便利です。

基本的に、コードは順列を生成する必要があります。これは、次の順列アプリケーションです。

  1. 私が呼ぶ次数3の順列はp30 ... 2回適用されます
  2. q20または1回適用された、順序2の順列
  3. 私が呼ぶ次数5の順列はp50 ... 4回適用されます
  4. 私が呼ぶオーダー2の別の順列はp20または1回適用されます

これらの順列には多くの選択肢があります。それらの1つは次のとおりです。

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]

ここでの順列には連続したインデックスの長い実行があり、ランレングスエンコーディングで圧縮できるので、この選択は他よりも優れています-4つの順列では29バイトのみです。

乱数の生成を簡素化するために、すべての乱数に対して1〜30の範囲の累乗(各順列が適用される回数)を選択しました。これにより、コードに多くの余分な作業が発生します。たとえば、p3、3回乗算されるたびに恒等置換になるです。ただし、コードはそのように小さく、範囲が30で割り切れる限り、出力は均一に分布します。

また、ランレングスデコード操作が少なくとも1回実行されるように、パワーは正でなければなりません。

コードには4つのネストされたループがあります。アウトラインは次のとおりです。

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

この擬似コードが、以下のインラインアセンブリコードよりも明確であることを願っています。

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

楽しい実装の詳細:

  • 高水準言語のように、インデントされたアセンブリを使用しました。そうでなければ、コードは理解できない混乱になります
  • 私が使用しcall、その後popコードに格納されたアクセスデータ(符号化された順列)に
  • jecxz命令により、ランレングスデコードプロセスの終了としてゼロバイトを使用できます。
  • 運が良ければ、数値30(2 * 3 * 5)はほぼ2の累乗です。これにより、短いコードを使用して1 ... 30の範囲の数値を生成できます。

            and ecx, 31
            dec ecx
            jle make_rand
    
  • 「汎用除算」命令(aam)を使用して、バイトをビットフィールド(3ビット長と5ビットインデックス)に分離します。運がよければ、コード内のその位置でcl = 0、なので、xchg

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.