Lotto Simulation - Schneller machen?

  • VB.NET

Es gibt 37 Antworten in diesem Thema. Der letzte Beitrag () ist von MB-Tech.

    Lotto Simulation - Schneller machen?

    Hey Leute,

    habe mal wieder meine IDE ausgegraben und eine kleine Lottosimulation geschrieben. Möchte damit Menschen zeigen, wie lange es dauert 6 Richtige bzw 6 Richtige + Superzahl zu bekommen.
    Realisiert ist dies mit ein paar Funktionen bzw. einer Do Loop Schleife, welche Zahlen generiert und prüft, dass diese nicht doppelt sind. Im Endeffekt wird mit jedem Durchgang der Do Loop eine
    Ziehung simuliert. Jedoch möchte ich die Simulation irgendwie beschleunigen.

    Alle 1,5sec schafft das Programm ca 1 Jahr an Ziehungen zu Simulieren. (52 Wochen â 2 Ziehungen).


    Begrenzt die Do Loop meine CPU? Oder gibt es da Kniffe (Multithreading o.Ä.), welche mir das alles Beschleunigen.
    (Ich muss ja irgendwie auf über 140 Millionen Ziehungen kommen :P)


    LG

    MB-Tech schrieb:

    Möchte damit Menschen zeigen, wie lange es dauert 6 Richtige bzw 6 Richtige + Superzahl zu bekommen.

    Wenn du ihnen das wirklich beibringen willst, dann erzähl ihnen die Grundlagen der Stochastik. Ist wirklich keine hohe Mathematik. Lotto bzw. 6 aus 49 ist das anschaulicheste Beispiel für den Binomialkoeffizient n über k.
    Die Wsk 6 Richtige zu haben ist 1 zu 49 über 6. (übrigens genauso wahrscheinlich wie 43 Richtige zu haben)

    n über k ist n!/(k! * (n-k)!). Kann man sich auch leicht aus der Kombinatorik herleiten (Permutationen).

    MB-Tech schrieb:

    Realisiert ist dies mit ein paar Funktionen bzw. einer Do Loop Schleife, welche Zahlen generiert und prüft, dass diese nicht doppelt sind

    Ist nicht so gut, weil du damit extra Iterationen pro gezogenen Kugel hast. Besser 1 Element aus Liste auswählen und daraus entfernen. (Zufallszahl erzeugen in range 0 bis listenlänge-1)
    Do Loop läuft sequenziell auf einem einzigen Kern ab. Besser wäre es warscheinlich, für jeden Kern einen eigenen Thread zu erstellen, dessen Priority hoch zu stellen und die dann nebeneinander laufen zu lassen. Außerdem lässt sich auch sicher dein Code etwas optimieren ;).
    -bzgl. des gelöschten Beitrags- Editiert. ~fufu

    Zum Thema: Macht du das aktuell nicht bereits mit Multithreading? Ansonsten dürfte dir eigentlich die GUI einfrieren, obwohl
    auch ein neuer Thread nichts ändert. Insofern man nicht markus' Methode nimmt, kann man das eventuell auf 4 Threads aufteilen,
    was aber auch nicht sehr viel schneller gehen dürfte (je Thread 35 Millionen).

    Grüße
    "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

    Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „fufu“ ()

    Ich hab eben mal kurz probiert. Mein sehr schlampiger Coder schafft pro Sekunde ca. 500.000 Ziehungen. Also hier dürfte wohl viel Potential sein, um Optimierungen einzubringen. Zeig uns mal am besten Deinen QuellCode und dann schau ma mal.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o

    MB-Tech schrieb:

    einer Do Loop Schleife, welche Zahlen generiert und prüft, dass diese nicht doppelt sind

    Mit Zufallszahlen natürlich. Was meinst du mit iteriert?. Das was ich im ersten Post mit iterationen gemeint habe ist, dass ich nicht mehrmals für ein und die selbe Kugel würfle, falls sie schon mal gezogen wurde.
    Ich erzeuge keine Zufallszahlen von 1-49 sondern nehme immer ein zufälliges Element aus der verbleibenden Liste (Trommel), welche ich nach jedem Zug um die gezogene Nummer kleiner mache. Das bringt nur einen marginalen Vorteil.

    Man kann ja außerdem die Ziehung sofort abbrechen, wenn eine gezogene Kugel nicht in meine Tipp liste ist. (was außerdem den hab-ich-gewonnen-check? am Ende überflüssig macht)
    Achso. Mit dem durchiterieren meinte ich, dass du das vielleicht über Permutation löst. Das scheint aber nicht so zu sein. Zeig doch einfach mal deinen Code, dann können hier alle dran rumwerkeln :).
    Viel Spass beim optimieren (ich würds ja gleich in c++ mit omp parallel machen):

    VB.NET-Quellcode

    1. Imports System.Threading.Tasks
    2. Module Module1
    3. Sub Main()
    4. Dim time1 = Now
    5. Parallel.For(0, Environment.ProcessorCount, Sub(i)
    6. Dim basislist As New List(Of Integer)
    7. For z = 1 To 49
    8. basislist.Add(z)
    9. Next
    10. Dim gewinnliste As New List(Of Integer) From {1, 2, 3, 4, 5, 42}
    11. Dim r As New Random(System.DateTime.Now.Millisecond + i)
    12. For ziehung = 1 To 20000000
    13. Dim ziehlist As New List(Of Integer)(basislist)
    14. Dim gewonnen = True
    15. For n = 1 To 6
    16. Dim kindex = r.Next(0, 49 - n)
    17. If Not gewinnliste.Contains(ziehlist.Item(kindex)) Then
    18. gewonnen = False
    19. Exit For
    20. End If
    21. ziehlist.RemoveAt(kindex)
    22. Next
    23. If gewonnen Then Console.WriteLine("gewonnen")
    24. Next
    25. End Sub)
    26. Console.WriteLine("elasped time: " & (Now - time1).TotalMilliseconds & " ms")
    27. Console.ReadKey()
    28. End Sub
    29. End Module


    €: Off by One Fehler korrigiert, Abhängigkeit von Environment.ProcessorCount eingefügt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „markus.obi“ ()

    Gut, ich poste mal hier meinen Code (Nach über 3 Jahren VB Pause ;))

    Ist vielleicht teilweise ein wenig abstrakt. Bin halt schon lange raus. :rolleyes:


    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class MainForm
    3. Dim gestoppt As Boolean
    4. Private Sub bt_start_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_start.Click
    5. If PrüfeFelder() = False Then
    6. MsgBox("Fehler! (Die Eingaben sind nicht korrekt)")
    7. Exit Sub
    8. End If
    9. gestoppt = False
    10. bt_start.Enabled = False
    11. bt_stop.Enabled = True
    12. bt_zufall.Enabled = False
    13. tb_zahl1.Enabled = False
    14. tb_zahl2.Enabled = False
    15. tb_zahl3.Enabled = False
    16. tb_zahl4.Enabled = False
    17. tb_zahl5.Enabled = False
    18. tb_zahl6.Enabled = False
    19. tb_superzahl.Enabled = False
    20. Dim ziehungen As Integer = 0
    21. Dim neuezahlen(5), aktuellezahlen(5) As Integer
    22. Dim neuesuperzahl As Integer = 0
    23. Dim aktuellesuperzahl As Integer = 0
    24. 'Loop
    25. Do
    26. If gestoppt = True Then
    27. Exit Do
    28. End If
    29. 'Anzeige aktualiseren
    30. ziehungen += 1
    31. lb_ziehungen.Text = "Ziehungen: " & ziehungen
    32. lb_wochen.Text = "Spielzeit: " & CInt(ziehungen / 2) & " Wochen (" & CInt(ziehungen / 2 / 52) & "Jahre)"
    33. 'Ziehungszahlen generieren / Aktuelle Zahlen holen und vergleichen ob richtig
    34. ZieheZahlen(neuezahlen, neuesuperzahl)
    35. HoleAktuelleZahlen(aktuellezahlen, aktuellesuperzahl)
    36. tb_z1.Text = CStr(neuezahlen(0))
    37. tb_z2.Text = CStr(neuezahlen(1))
    38. tb_z3.Text = CStr(neuezahlen(2))
    39. tb_z4.Text = CStr(neuezahlen(3))
    40. tb_z5.Text = CStr(neuezahlen(4))
    41. tb_z6.Text = CStr(neuezahlen(5))
    42. tb_sz.Text = CStr(neuesuperzahl)
    43. If CheckArray(neuezahlen, aktuellezahlen) = True And neuesuperzahl = aktuellesuperzahl Then
    44. 'Jackpot
    45. Me.BackColor = Color.Lime
    46. bt_stop.Enabled = False
    47. bt_start.Enabled = False
    48. bt_zufall.Enabled = False
    49. MsgBox("Sie haben den Jackpot gewonnen!!!")
    50. Exit Sub
    51. ElseIf CheckArray(neuezahlen, aktuellezahlen) = True Then
    52. Me.BackColor = Color.Lime
    53. bt_stop.Enabled = False
    54. bt_start.Enabled = False
    55. bt_zufall.Enabled = False
    56. MsgBox("Sie haben den Jackpot ohne Superzahl gewonnen!")
    57. Exit Sub
    58. End If
    59. Loop
    60. End Sub
    61. Private Sub bt_stop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_stop.Click
    62. gestoppt = True
    63. bt_start.Enabled = True
    64. bt_stop.Enabled = False
    65. tb_zahl1.Enabled = True
    66. tb_zahl2.Enabled = True
    67. tb_zahl3.Enabled = True
    68. tb_zahl4.Enabled = True
    69. tb_zahl5.Enabled = True
    70. tb_zahl6.Enabled = True
    71. tb_superzahl.Enabled = True
    72. bt_zufall.Enabled = True
    73. End Sub
    74. 'Funktionen
    75. 'Prüft die Felder auf korrekte Eingaben
    76. Private Function PrüfeFelder() As Boolean
    77. Dim tbarray(6) As TextBox
    78. tbarray(0) = tb_zahl1
    79. tbarray(1) = tb_zahl2
    80. tbarray(2) = tb_zahl3
    81. tbarray(3) = tb_zahl4
    82. tbarray(4) = tb_zahl5
    83. tbarray(5) = tb_zahl6
    84. tbarray(6) = tb_superzahl
    85. For i As Integer = 0 To 5
    86. If tbarray(i).Text = "" Then
    87. Return False
    88. End If
    89. If IsNumeric(tbarray(i).Text) = True Then
    90. If CInt(tbarray(i).Text) < 1 Or CInt(tbarray(i).Text) > 49 Then
    91. Return False
    92. End If
    93. Else
    94. Return False
    95. End If
    96. Next
    97. If tbarray(6).Text = "" Then
    98. Return False
    99. End If
    100. If IsNumeric(tbarray(6).Text) = True Then
    101. If CInt(tbarray(6).Text) < 0 Or CInt(tbarray(6).Text) > 9 Then
    102. Return False
    103. End If
    104. Else
    105. Return False
    106. End If
    107. Dim tbintarray(5) As Integer
    108. tbintarray(0) = CInt(tb_zahl1.Text)
    109. tbintarray(1) = CInt(tb_zahl2.Text)
    110. tbintarray(2) = CInt(tb_zahl3.Text)
    111. tbintarray(3) = CInt(tb_zahl4.Text)
    112. tbintarray(4) = CInt(tb_zahl5.Text)
    113. tbintarray(5) = CInt(tb_zahl6.Text)
    114. If tbintarray.Length > tbintarray.Distinct().Count() Then
    115. Return False
    116. End If
    117. Return True
    118. End Function
    119. 'Simuliert eine Ziehung
    120. Private Sub ZieheZahlen(ByRef Zahlen() As Integer, ByRef SuperZahl As Integer)
    121. Application.DoEvents()
    122. Randomize()
    123. Dim ziehungsarray(5) As Integer
    124. Dim superz As Integer = CInt(Int((10 * Rnd()) + 0))
    125. Dim z As Integer
    126. For i As Integer = 0 To 5
    127. Do
    128. z = CInt(Int((49 * Rnd()) + 1))
    129. If Not ziehungsarray.Contains(z) Then
    130. ziehungsarray(i) = z
    131. Exit Do
    132. End If
    133. Loop
    134. Next
    135. Array.Sort(ziehungsarray)
    136. Zahlen = ziehungsarray
    137. SuperZahl = superz
    138. End Sub
    139. 'Holt die aktuellen Zahlen aus den Textboxen
    140. Private Sub HoleAktuelleZahlen(ByRef Zahlen() As Integer, ByRef SuperZahl As Integer)
    141. Dim z(5) As Integer
    142. z(0) = (CInt(tb_zahl1.Text))
    143. z(1) = (CInt(tb_zahl2.Text))
    144. z(2) = (CInt(tb_zahl3.Text))
    145. z(3) = (CInt(tb_zahl4.Text))
    146. z(4) = (CInt(tb_zahl5.Text))
    147. z(5) = (CInt(tb_zahl6.Text))
    148. SuperZahl = CInt(tb_superzahl.Text)
    149. Array.Sort(z)
    150. Zahlen = z
    151. End Sub
    152. 'Prüft zwei Arrays
    153. Public Function CheckArray(ByVal arr1 As Integer(), ByVal arr2 As Integer()) As Boolean
    154. Dim b As Boolean = False
    155. If arr1.Length() = arr2.Length() Then
    156. b = True
    157. For c As Integer = 0 To arr1.Length() - 1
    158. b = b And arr1(c).Equals(arr2(c))
    159. Next
    160. End If
    161. Return b
    162. End Function
    163. 'Ausgabe
    164. Public Sub Ausgabe(ByVal zahlen() As Integer, ByVal superzahl As Integer)
    165. Dim tmpstr As String = ""
    166. For i As Integer = 0 To 5
    167. tmpstr &= zahlen(i).ToString & ", "
    168. Next
    169. MsgBox("Jackpot!" & vbNewLine & vbNewLine & "Die Zahlen lauten:")
    170. End Sub
    171. Private Sub bt_zufall_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_zufall.Click
    172. Dim neuezahlen(5) As Integer
    173. Dim neuesuperzahl As Integer
    174. ZieheZahlen(neuezahlen, neuesuperzahl)
    175. tb_zahl1.Text = CStr(neuezahlen(0))
    176. tb_zahl2.Text = CStr(neuezahlen(1))
    177. tb_zahl3.Text = CStr(neuezahlen(2))
    178. tb_zahl4.Text = CStr(neuezahlen(3))
    179. tb_zahl5.Text = CStr(neuezahlen(4))
    180. tb_zahl6.Text = CStr(neuezahlen(5))
    181. tb_superzahl.Text = CStr(neuesuperzahl)
    182. End Sub
    183. End Class

    MB-Tech schrieb:

    VB.NET-Quellcode

    1. If arr1.Length() = arr2.Length() Then
    2. b = True
    3. For c As Integer = 0 To arr1.Length() - 1
    4. b = b And arr1(c).Equals(arr2(c))
    5. Next
    6. End If


    Das sieht nicht so super aus...
    Wenn b schon False ist und arr1(c) ungleich arr2(c), dann wird b ja wieder true...


    EDIT: Zu spät für mein Gehirn -.-
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    ich hab mir auch mal den spaß gemacht und ein lotto-spiel geschrieben. einfach 7 zufallszahlen geniert und miteinander verglichen. und dann das ganze als loop until in nem backgroundworker lauifen lassen.
    zur zeiterfassung bis meine getippten zahlen gezogen wurden habe ich einfach nen timer ticken lassen und in einem label die sek., min, std erfasst und die anzahl an ziehungen. lief super. die maxcimale wartezeit waren etwa so 5 bis 10 minuten. jenach tipp.

    affrop schrieb:

    ich hab mir auch mal den spaß gemacht und ein lotto-spiel geschrieben. einfach 7 zufallszahlen geniert und miteinander verglichen. und dann das ganze als loop until in nem backgroundworker lauifen lassen.
    zur zeiterfassung bis meine getippten zahlen gezogen wurden habe ich einfach nen timer ticken lassen und in einem label die sek., min, std erfasst und die anzahl an ziehungen. lief super. die maxcimale wartezeit waren etwa so 5 bis 10 minuten. jenach tipp.
    Ok, kontrolliert dein Code auch auf Einzigartigkeit Zahlen, also nicht, dass du sowas hast wie 11 11 21 36 36 19 4


    Habe mal bei mir die "Arbeit" des Codes in einen BGW gepackt -> Er ist nur halb so schnell...

    LG

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „MB-Tech“ ()

    affrop schrieb:

    ja na klar, kontrolliert der auf einziogartigkeit. wenn er die zweite zufallszahl generiert und die gleich der ersten ist, dann wird eine neue generiert usw.
    Und wenn er schon 3 hat z.b. 11 22 33 und dann die neue Rnd Zahl 11 ist, prüft er auch ALLE vorherigen?
    Okay. Also wieviele Ziehungen schaffst du pro Sekunde?


    Habe jetzt mal eine reine Konsolenanwendung geschrieben, welche erstmal nur Zahlen generiert, aber noch nicht mit den eingegeben vergleicht. Selbst hier dauert 1 Million Ziehungen ziemlich lange...

    Gerade mit 1Mio durch. Sehe gerade, dass doch öfters gleiche Zahlen in einer Ziehung sind...?

    VB.NET-Quellcode

    1. Module Module1
    2. Sub Main()
    3. 'Console einstellen
    4. Console.BackgroundColor = ConsoleColor.DarkBlue
    5. Console.ForegroundColor = ConsoleColor.White
    6. Console.SetWindowSize(55, 40)
    7. Console.Clear()
    8. 'Einstellungen
    9. Dim LottoZahlen() As Integer = {6, 21, 34, 38, 43, 49}
    10. Dim SuperZahl As Integer = 5
    11. Dim AnzahlDerZiehungen As UInteger = 1000000 '1 Million
    12. 'Begrüßung
    13. Console.WriteLine("### Lotto Simulation ###")
    14. Console.WriteLine("")
    15. Console.WriteLine("Dieses Programm simuliert eine im Programmcode")
    16. Console.WriteLine("voreingestellte Anzahl an Ziehungen. Die Lottozahlen")
    17. Console.WriteLine("sowie die Superzahl sind ebenso vorweg festgelegt.")
    18. Console.WriteLine("")
    19. Console.WriteLine("Die voreingestellten Daten lauten:")
    20. Console.WriteLine("")
    21. Console.WriteLine("Anzahl der Ziehungen: " & AnzahlDerZiehungen.ToString)
    22. Console.Write("6aus49: ")
    23. For i As Integer = 0 To 5
    24. If i < 5 Then
    25. Console.Write(LottoZahlen(i).ToString & ", ")
    26. Else
    27. Console.Write(LottoZahlen(i).ToString & vbNewLine)
    28. End If
    29. Next
    30. Console.WriteLine("Superzahl: " & SuperZahl.ToString)
    31. Console.WriteLine("")
    32. Console.WriteLine("")
    33. Console.WriteLine("Um die Simulation zu starten, betätigen Sie bitte")
    34. Console.WriteLine("eine x-belibiege Taste auf Ihrer Tastatur!")
    35. Console.WriteLine("")
    36. Console.ReadLine()
    37. Console.Clear()
    38. 'Variablen
    39. Dim GenerierteLottoZahlen(5) As Integer
    40. Dim GenerierteSuperZahl As Integer
    41. Dim ZufallsGenerator As New Random
    42. Dim ZufallsZahl As Integer
    43. 'Lottozahlen sortieren
    44. Array.Sort(LottoZahlen)
    45. 'Ziehungen
    46. For ZiehungsNummer As UInteger = 1 To AnzahlDerZiehungen
    47. 'Zufällige Lottozahlen 6aus49 generieren (Zahlenbereich 1-49)
    48. For i As Integer = 0 To 5
    49. Do
    50. ZufallsZahl = ZufallsGenerator.Next(1, 50)
    51. GenerierteLottoZahlen(i) = ZufallsZahl
    52. Loop While GenerierteLottoZahlen.Contains(ZufallsZahl) = False
    53. Next
    54. 'Zufällige Superzahl 1aus9 generieren (Zahlenbereich 0-9)
    55. GenerierteSuperZahl = ZufallsGenerator.Next(0, 10)
    56. 'Ausgabe der Ziehung
    57. AusgabeDerZiehung(GenerierteLottoZahlen, GenerierteSuperZahl, ZiehungsNummer)
    58. Next ZiehungsNummer
    59. Console.ReadLine()
    60. End Sub
    61. Private Sub AusgabeDerZiehung(ByVal LottoZahlen() As Integer, ByVal SuperZahl As Integer, ByVal ZiehungsNummer As UInteger)
    62. 'Lottozahlen sortieren
    63. Array.Sort(LottoZahlen)
    64. 'Ausgabe der Ziehungsnummer
    65. Console.WriteLine("### Ziehung Nr. " & ZiehungsNummer.ToString & " ###")
    66. 'Ausgabe der Zahlen 6aus49
    67. Console.Write("6aus49: ")
    68. For i As Integer = 0 To 5
    69. If i < 5 Then
    70. Console.Write(LottoZahlen(i).ToString & ", ")
    71. Else
    72. Console.Write(LottoZahlen(i).ToString & vbNewLine)
    73. End If
    74. Next
    75. 'Ausgabe der Superzahl
    76. Console.WriteLine("Superzahl: " & SuperZahl.ToString)
    77. 'Ziehungsblock Ende
    78. Console.WriteLine("")
    79. Console.WriteLine("")
    80. End Sub
    81. End Module

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „MB-Tech“ ()