3 つの連続したアイテムのスタック (元のシーケンスからは許可されません)
shuffle(n) の結果は、shuffle(n+1) の開始シーケンスとして使用されるものだと思います。同じ開始シリーズを使用すると、 の有効な組み合わせは 7 つしかないため、これは簡単ではありません{0, 1, 2, 3}
。アプリの起動時に固定の開始シーケンスを使用すると、最初のシャッフルはこれら 7 つのいずれかになります (おそらく十分に変化します)。
スクランブラー クラス:
Public Class Scrambler
Private rand As Random
Public Sub New()
rand = New Random
End Sub
' FY In-Place integer array shuffle
Public Sub Shuffle(items() As Integer)
Dim tmp As Integer
Dim j As Integer
' hi to low, so the rand result is meaningful
For i As Integer = items.Length - 1 To 0 Step -1
j = rand.Next(0, i + 1) ' NB max param is EXCLUSIVE
tmp = items(j)
' swap j and i
items(j) = items(i)
items(i) = tmp
Next
End Sub
' build a list of bad sequences
' fullfils the "stack of 3 sequential items (from the original sequence..." requirement
' nsize - allows for the "(or any number ..." portion though scanning for
' a series-of-5 may be fruitless
Public Function GetBadList(source As Integer(),
nSize As Integer) As List(Of String)
Dim BList As New List(Of String)
Dim badNums(nSize - 1) As Integer
For n As Integer = 0 To source.Length - nSize
Array.Copy(source, n, badNums, 0, badNums.Length)
BList.Add(String.Join(",", badNums))
Array.Clear(badNums, 0, badNums.Length)
Next
Return BList
End Function
Public Function ScrambleArray(items() As Integer, badSize As Integer) As Integer()
' FY is an inplace shuffler, make a copy
Dim newItems(items.Length - 1) As Integer
Array.Copy(items, newItems, items.Length)
' flags
Dim OrderOk As Boolean = True
Dim AllDiffPositions As Boolean = True
Dim BadList As List(Of String) = GetBadList(items, badSize)
' build the bad list
Do
Shuffle(newItems)
' check if they all moved
AllDiffPositions = True
For n As Integer = 0 To items.Length - 1
If newItems(n) = items(n) Then
AllDiffPositions = False
Exit For
End If
Next
' check for forbidden sequences
If AllDiffPositions Then
Dim thisVersion As String = String.Join(",", newItems)
OrderOk = True
For Each s As String In BadList
If thisVersion.Contains(s) Then
OrderOk = False
Exit For
End If
Next
End If
Loop Until (OrderOk) And (AllDiffPositions)
Return newItems
End Function
End Class
テストコード/使い方:
' this series is only used once in the test loop
Dim theseItems() As Integer = {0, 1, 2, 3}
Dim SeqMaker As New Scrambler ' allows one RNG used
Dim newItems() As Integer
' reporting
Dim rpt As String = "{0} Before: {1} After: {2} time:{3}"
ListBox1.Items.Clear()
For n As Integer = 0 To 1000
sw.Restart()
newItems = SeqMaker.ScrambleArray(theseItems, 3) ' bad series size==3
sw.Stop()
ListBox1.Items.Add(String.Format(rpt, n.ToString("0000"), String.Join(",", theseItems),
String.Join(",", newItems), sw.ElapsedTicks.ToString))
Console.WriteLine(rpt, n.ToString("0000"), String.Join(",", theseItems),
String.Join(",", newItems), sw.ElapsedTicks.ToString)
' rollover to use this result as next start
Array.Copy(newItems, theseItems, newItems.Length)
Next
アイテムが元の位置にあることは決してありません。この種の小さなセットでは理にかなっています。ただし、より大きなセットの場合、多数の正当なシャッフル (>60%) が除外されます。場合によっては、1 つのアイテムが同じ場所にあるという理由だけで。
Start: {1,2,8,4,5,7,6,3,9,0}
Result: {4,8,2,0,7,1,6,9,5,3}
これは「6」のために失敗しますが、それは本当に無効なシャッフルですか? 一連の 3 ルールは、大規模なセット (<1%) ではめったに現れないため、時間の無駄になる可能性があります。
リストボックスとコンソール レポート (および表示されていない配布の収集) がなければ、かなり高速です。
Std Shuffle, 10k iterations, 10 elements: 12ms (baseline)
Modified, 10k iterations, 10 elements: 91ms
Modified, 10k iterations, 04 elements: 48ms
変更されたシャッフルは、時間がかからないことがわかっている再シャッフルに依存しています。そのため、Rule1 OrElse Rule2 が失敗すると、単に再シャッフルします。10 要素のシャッフルでは、10,000 個の「良い」シャッフルを取得するために実際に 28k シャッフルを実行する必要があります。4 要素のシャッフルは、項目が少ない (34,000 件の拒否) とルールを簡単に破ることができるため、実際には拒否率が高くなります。
これらの「改善」がバイアスを導入する場合、それは良くないため、それはシャッフル分布ほど興味がありません。10k 4 要素分布:
seq: 3,2,1,0 count: 425
seq: 1,0,2,3 count: 406
seq: 3,2,0,1 count: 449
seq: 2,3,1,0 count: 424
seq: 0,1,3,2 count: 394
seq: 3,0,2,1 count: 371
seq: 1,2,3,0 count: 411
seq: 0,3,1,2 count: 405
seq: 2,1,3,0 count: 388
seq: 0,3,2,1 count: 375
seq: 2,0,1,3 count: 420
seq: 2,1,0,3 count: 362
seq: 3,0,1,2 count: 396
seq: 1,2,0,3 count: 379
seq: 0,1,2,3 count: 463
seq: 1,3,0,2 count: 398
seq: 2,3,0,1 count: 443
seq: 1,0,3,2 count: 451
seq: 3,1,2,0 count: 421
seq: 2,0,3,1 count: 487
seq: 0,2,3,1 count: 394
seq: 3,1,0,2 count: 480
seq: 0,2,1,3 count: 444
seq: 1,3,2,0 count: 414
より小さな反復 (1K) では、変更された形式と比較して、より均一な分布を見ることができます。ただし、特定の正当なシャッフルを拒否している場合は、これが予想されます。
非常に多くの可能性 (360 万回のシャッフル) があるため、10 要素の分布は決定的ではありません。とはいえ、10,000 回の反復では、約 9980 のシリーズが存在する傾向があり、12 ~ 18 のカウントは 2 です。