Achterrandom = 50

  • Moin Moin.

    Mit

    Spoiler anzeigen
    [autoit]


    MsgBox(0, "Eine Zufallszahl", "Zufallszahl" & Random(1, 50, 1))

    [/autoit]


    erzeuge ich ja eine zufällige Zahl zwischen 1 und 50.
    Aber nun benötige ich acht zufällige Zahlen deren Summer immer zusammen 50 ergeben.

    Hat das bereits mal jemand gescriptet oder weiß wie ich das anstellen kann?

    Gedacht habe ich, das es so gehen könnte, aber da habe ich wohl einen Gedankenfehler.
    Habe Gedacht das die erste Zahl eine zwischen 1 und 50 ist, die zweite eine zwischen 1 und der ersten Zufallszahl, die dritte eine zwischen 1 und der zweiten Zufallszahl, usw. Aber das geht irgendwie berechtigterweise nicht, das ich nicht weiß, wie ich a) abfange das nicht gleich am Anfang die Zufallszahl zu klein ist. Aber es soll auch nicht die Zahlen eine bestimmte Reihenfolge haben, also z. B. aufsteigend bzw. absteigend, sondern so wie sie dahin (daher?) kommen.
    Hier mal das gescriptete meiner Gedanken:

    Spoiler anzeigen
    [autoit][/autoit] [autoit][/autoit] [autoit]

    $var0 = 50

    [/autoit] [autoit][/autoit] [autoit]

    $var1 = Random(1, $var0,1)
    $var2 = Random(1, 50-$var1,1)
    $var3 = Random(1, 50-$var2,1)
    $var4 = Random(1, 50-$var3,1)
    $var5 = Random(1, 50-$var4,1)
    $var6 = Random(1, 50-$var5,1)
    $var7 = Random(1, 50-$var6,1)
    $var8 = 50-$var7

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(0, "Acht Zufallszahlen", "die acht Zufallszahlen sind: " & $var1 & "-" & $var2 & "-" & $var3& "-" & $var4 & "-" & $var5 & "-" & $var6 & "-" & $var7 & "-" & $var8)

    [/autoit]

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

    2 Mal editiert, zuletzt von Alina (14. Januar 2015 um 14:07)

  • Zunächst: Sobald eine Bedingung gestellt wird (Summe gleich 50), können wir nicht mehr ausschließlich mit Zufallszahlen arbeiten. Mindestens eine Zahl muss einem Zwang unterliegen, ist also nicht zufällig. Trotzdem kann man eine Verteilung erzielen, die einigermaßen zufällig aussieht. :D

    Ich habe folgende Vorgehensweise verwendet: Wir wollen die 50 in 8 "Zufallszahlen" unterteilen. Dazu teilen wir unsere Gesamtsumme erstmal in kleine Pakete auf, mit denen wir arbeiten können. Vier Pakete mit jeweils einer Größe von 12.5 klingen doch annehmbar (12.5 * 4 = 50). Wir erzeugen nun für das erste Paket eine Zufallszahl zwischen 0 und 12.5, beispielsweise 7.5... Dann "vervollständigen" wir das Paket mit der Rechnung 7.5 + X = 12.5 => X = 12.5 - 7.5 = 5. Damit haben wir unsere ersten beiden "Zufallszahlen". Das wiederholen wir nun noch für die anderen drei Pakete, und schon erhalten wir 8 Zufallszahlen, die in der Summe 50 ergeben.
    5+7.5+4+8.5+1+11.5+2+10.5=50

    In Skriptform:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    $iSum = 50
    Local $aNumbers[8]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($aNumbers) - 1
    If Mod($i + 1, 2) Then ;ungerade
    $aNumbers[$i] = Random(1, $iSum / UBound($aNumbers), True)
    Else ;gerade
    $aNumbers[$i] = ((2 * $iSum) / UBound($aNumbers)) - $aNumbers[$i - 1]
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _ArrayDisplay($aNumbers)

    [/autoit] [autoit][/autoit] [autoit]

    ;test
    $iSum = 0
    For $i = 0 To UBound($aNumbers) - 1
    $iSum += $aNumbers[$i]
    Next
    MsgBox(64, "Info", $iSum)

    [/autoit]
    • Offizieller Beitrag

    chesstiger : Ich denke, sie meint Ganzzahlen und keine Doppelten.

    Ich hätte da eine BruteForce-Methode zu bieten:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    $iSum = 50
    Global $aNumbers[$iSum], $aTemp, $aRandom[5], $iRandom, $iTotal = 0, $iCount = 0
    For $i = 0 To $iSum - 1
    $aNumbers[$i] = $i + 1
    Next
    Global $iTimer = TimerInit()
    Do
    $iTotal = 0
    $aTemp = $aNumbers
    For $i = 0 To 4
    $iRandom = Random(0, UBound($aTemp) - 1 - $i, 1)
    $aRandom[$i] = $aTemp[$iRandom]
    $iTotal += $aTemp[$iRandom]
    $aTemp[$iRandom] = $aTemp[UBound($aTemp) - 1 - $i]
    Next
    $iCount += 1
    Until $iTotal = $iSum
    ConsoleWrite(StringFormat('Summe: %i, Benötigte Durchgänge: %i, benötigte Zeit: %i ms\n', $iSum, $iCount, TimerDiff($iTimer)))
    _ArrayDisplay($aRandom)

    [/autoit]
  • Die Frage mit den "Doppelten" stellte sich mir auch.
    Wenn Doppelte erlaubt sind, ginge auch folgende Variante:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $iMax = 50
    $iAnzahl = 8
    $iSumme = 0

    [/autoit] [autoit][/autoit] [autoit]

    Dim $aZahl[$iAnzahl]
    For $i = 0 To $iAnzahl - 1
    $aZahl[$i] = 1 ; alle sollen ja > 1 sein
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $i = Random(0,$iAnzahl - 1, 1) ; per Zufall eine Zahl wählen
    $wert = Random(0, 1, 1) ; und 0 oder 1 hinzuaddieren
    $aZahl[$i] += $wert
    $iSumme += $wert
    Until $iSumme = $iMax
    _ArrayDisplay($aZahl)

    [/autoit]

    Zur Nutzung dieses Forum's, ist ein Übersetzer für folgende Begriffe unerlässlich:

    "On-Bort, weier, verscheiden, schädliges, Butten steyling, näckstet, Parr, Porblem, scripe, Kompletenz, harken, manuel zu extramieren, geckukt, würglich, excell, acces oder Compilevorgeng"

    Einmal editiert, zuletzt von Micha_he (14. Januar 2015 um 15:54)

  • Ganzzahlen : wichtig

    Oscar : hier bekomme ich keine Ausgabe, wenn ich es auf acht Zahlen setze. Das Script läuft und läuft und ohne Ende!?
    Möglichkeit wäre die vier Waagerechten Zahlen beim ersten mal aufzuschreiben (zu nutzen) und dann nochmals durchlaufen lassen und aufzuschreiben (zu nutzen). Man kommt zumindest schon mal auf diesen Weg der Sache dichter.
    Doppelter Durchlauf mit halben Summer-Wert dann so:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    $iSum = 25
    Global $aNumbers[$iSum], $aTemp, $aRandom[5], $iRandom, $iTotal = 0, $iCount = 0
    For $i = 0 To $iSum - 1
    $aNumbers[$i] = $i + 1
    Next
    Global $iTimer = TimerInit()
    Do
    $iTotal = 0
    $aTemp = $aNumbers
    For $i = 0 To 4
    $iRandom = Random(0, UBound($aTemp) - 1 - $i, 1)
    $aRandom[$i] = $aTemp[$iRandom]
    $iTotal += $aTemp[$iRandom]
    $aTemp[$iRandom] = $aTemp[UBound($aTemp) - 1 - $i]
    Next
    $iCount += 1
    Until $iTotal = $iSum
    ConsoleWrite(StringFormat('Summe: %i, Benötigte Durchgänge: %i, benötigte Zeit: %i ms\n', $iSum, $iCount, TimerDiff($iTimer)))
    _ArrayDisplay($aRandom)

    [/autoit]

    Micha_he: hier bekomme ich am Ende eine Summe von über 50 raus.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Habe etwas gebastelt. Leider ist die Methode sehr ineffizient, war eben die erste die mir eingefallen ist :) Als Parameter hat man die Anzahl Zahlen sowie die gewünschte Summe und einen Mindestwert (z.B. 1).

    Edit: Im vergleich zu Brute Force ist sie schon schnell. Bei mir braucht sie meistens ca. 1 Millisekunde...

    Spoiler anzeigen
    [autoit]


    ConsoleWrite(@CRLF)
    For $i = 0 To 9 Step 1
    Test(Random(1, 7, 1), Random(80, 150, 1), Random(5, 10, 1), 200)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Func Test($iMin, $iSum, $nCount, $iMaxRounds = 100)
    Local $t, $timer, $a, $c, $e, $u
    $timer = TimerInit()
    $a = RandomN($iMin, $iSum, $nCount, $iMaxRounds)
    $c = @extended
    $e = @error
    $t = TimerDiff($timer)
    $u = UBound($a)
    ConsoleWrite(($e ? '!' : '+') & ' Benötigte Zeit: ' & Round($t * 1000, 0) & ' µs' & @CRLF & ($e ? '!' : '+') & ' Benötigte ' & _
    'Runden: ' & $c & @CRLF & ($e ? '!' : '+') & ' Mindestwert: ' & $iMin & @CRLF & ($e ? '!' : '+') & ' Anzahl Zahlen: ' & UBound _
    ($a) & @CRLF & ($e ? '!' : '+') & ' Summe: ' & Sum($a) & @CRLF & ($e ? '!' : '+') & ' ')
    For $i = 0 To UBound($a) - 1 Step 1
    ConsoleWrite($a[$i] & ($i = $u - 1 ? '' : ','))
    Next
    ConsoleWrite(@CRLF & @CRLF)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; iMin - Mindestwert (dieser Wert wird bei den ausgegebenen Zahlen nicht unterschritten)
    ; iSum - Summe aller Zufallszahlen
    ; nCount - Anzahl der Zufallszahlen
    ; iRounds - Anzahl Runden die berechnet wird. (nur vorhanden, damit es sich nicht festfrisst falls ein unmögliches Ergebnis verlangt wird)
    ; @error - 0 - Alles ok
    ; 1 - Es konnte kein Ergebnis gefunden werden. Das kann entweder daran liegen,
    ; dass die Anzahl Runden unzureichend war (einfach runden erhöhen), oder
    ; das geforderte Ergebnis ist unmöglich. z.B. 10 Zahlen mit der Mindestgröße
    ; 5 die eine Summe von 20 ergeben. -> In dem Fall überlegen was man will.
    ; @extended - Beinhaltet grundsätzlich die Anzahl Runden die zur Berechnung genutzt wurden.
    Func RandomN($iMin, $iSum, $nCount, $iMaxRounds = 100)
    Local $aRND[$nCount], $r, $nTMP, $s, $c = 0
    For $i = 0 To $nCount - 1 Step 1
    $aRND[$i] = $iSum
    Next
    $s = Sum($aRND)
    While $s <> $iSum And $c < $iMaxRounds
    $c += 1
    $r = Random(0, $nCount - 1, 1)
    If $s < $iSum Then
    $aRND[$r] = Round($aRND[$r] * Random(1, 2), 0)
    Else
    $nTMP = Round($aRND[$r] / Random(1, 2), 0)
    If $nTMP > $iMin Then $aRND[$r] = $nTMP
    EndIf
    $s = Sum($aRND)
    WEnd
    If $s = $iSum Then Return SetExtended($c, $aRND)
    Return SetError(1, $c, $aRND)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Sum($a)
    If Not IsArray($a) Then Return $a
    Local $s = $a[0]
    For $i = 1 To UBound($a) - 1 Step 1
    $s += $a[$i]
    Next
    Return $s
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit]
    • Offizieller Beitrag

    Stimmt, es waren 8 Zahlen gefordert. X/
    Dadurch werden aber die Zufallszahlen ziemlich eingeschränkt. Denn wenn es 8 Zahlen sein müssen (ohne Doppelte) und es muss 50 als Gesamtsumme rauskommen, dann können da kaum große Zahlen vorkommen.
    Ich habe mein Script mal angepasst, das kann allerdings recht lange dauern (> 2Min.):

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    $iSum = 50
    Global $aNumbers[$iSum], $aTemp, $aRandom[8], $iRandom, $iTotal = 0, $iCount = 0
    For $i = 0 To $iSum - 1
    $aNumbers[$i] = $i + 1
    Next
    Global $iTimer = TimerInit()
    Do
    $iTotal = 0
    $aTemp = $aNumbers
    For $i = 0 To UBound($aRandom) - 1
    $iRandom = Random(0, UBound($aTemp) - 1 - $i, 1)
    $aRandom[$i] = $aTemp[$iRandom]
    $iTotal += $aTemp[$iRandom]
    $aTemp[$iRandom] = $aTemp[UBound($aTemp) - 1 - $i]
    Next
    $iCount += 1
    Until $iTotal = $iSum
    ConsoleWrite(StringFormat('Summe: %i, benötigte Durchgänge: %i, benötigte Zeit: %i ms\n', $iSum, $iCount, TimerDiff($iTimer)))
    _ArrayDisplay($aRandom)

    [/autoit]

  • Micha_he: hier bekomme ich am Ende eine Summe von über 50 raus.

    Ich habe es mehrfach getestet und es passte immer. Allein die Zeile 17 stimmt mir dabei eigentlich schon zu !
    Wenn dem so ist, habe ich zur Zeit keine Idee...

    Edit (sichere Gesamtsumme):

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $iMax = 50
    $iAnzahl = 8

    [/autoit] [autoit][/autoit] [autoit]

    Dim $aZahl[$iAnzahl]
    For $i = 0 To $iAnzahl - 1
    $aZahl[$i] = 1 ; alle sollen ja >= 1 sein
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $i = Random(0,$iAnzahl - 1, 1) ; per Zufall eine Zahl wählen
    $wert = Random(0, 1, 1) ; und 0 oder 1 hinzuaddieren
    $aZahl[$i] += $wert
    Until _ArraySum_1D($aZahl) >= $iMax
    _ArrayDisplay($aZahl)

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArraySum_1D($aData)
    Local $iSum
    For $i = 0 To UBound($aData) - 1
    $iSum += $aData[$i]
    Next
    Return $iSum
    EndFunc

    [/autoit]

    Zur Nutzung dieses Forum's, ist ein Übersetzer für folgende Begriffe unerlässlich:

    "On-Bort, weier, verscheiden, schädliges, Butten steyling, näckstet, Parr, Porblem, scripe, Kompletenz, harken, manuel zu extramieren, geckukt, würglich, excell, acces oder Compilevorgeng"

    3 Mal editiert, zuletzt von Micha_he (14. Januar 2015 um 15:54)

  • Die Zahlen sind zwar doof verteilt aber zufällig und in ihrer Summe immer 50:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $SUM = 50
    Global Const $N = 8
    Global $A[$N]

    [/autoit] [autoit][/autoit] [autoit]

    Global $d_SumTmp = 0
    For $i = 0 To $N - 2
    $m = $SUM - $d_SumTmp - $N + $i + 1
    $r = $m = 1 ? 1 : Random(1, $m, 1)
    $A[$i] = $r
    $d_SumTmp += $r
    Next
    $A[$N - 1] = $SUM - $d_SumTmp

    [/autoit] [autoit][/autoit] [autoit]

    ; Summenprobe:
    $x = 0
    For $i In $A
    $x += $i
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; Zahlen ausgeben:
    _ArrayDisplay($A, "Summe: " & $x)

    [/autoit]
  • Naja, wenn nur Ganzzahlen gefordert sind...
    Bei meiner Lösung entstehen zwangsläufig 4 Kommazahlen. Diese kann man auch wieder als zwei 2er-Pärchen (a,b) betrachten. Dann kann man einfach von a 0.5 abziehen und zu b dann dementsprechend 0.5 dazurechnen. Die Summe ändert sich nicht, es werden aber ausschließlich natürliche Zahlen erzeugt.

    Spoiler anzeigen
    [autoit]


    $iSum = 50
    Local $aNumbers[8]

    [/autoit] [autoit][/autoit] [autoit]

    $bCarry = False

    [/autoit] [autoit][/autoit] [autoit]

    ;Zahlen generieren
    For $i = 0 To UBound($aNumbers) - 1
    If Mod($i + 1, 2) Then ;ungerade
    $aNumbers[$i] = Random(1, $iSum / UBound($aNumbers), True)
    Else ;gerade
    $aNumbers[$i] = ((2 * $iSum) / UBound($aNumbers)) - $aNumbers[$i - 1]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If Not IsInt($aNumbers[$i]) Then
    If $bCarry Then
    $aNumbers[$i] += 0.5
    Else
    $aNumbers[$i] -= 0.5
    EndIf
    $bCarry = Not $bCarry
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _ArrayDisplay($aNumbers)

    [/autoit] [autoit][/autoit] [autoit]

    ;test
    $iSum = 0
    For $i = 0 To UBound($aNumbers) - 1
    $iSum += $aNumbers[$i]
    Next
    MsgBox(64, "Info", $iSum)

    [/autoit]


    (Der Quellcode ist deutlich nicht optimiert. Es ist klar, dass immer die zweite Zahl die Kommazahl sein muss, wenn man mein Päckchenschema betrachtet. Dieses Wissen wurde hier nicht genutzt, um den Vorgang in einen eigenen Code-Block zu packen, damit meine Idee besser nachverfolgbar ist.)

    Gruß

  • Hier nochmal eine Version mit Kontrolle auf doppelte Zahlen. Die Rechenzeit geht dadurch natürlich in die Höhe (liegt bei mir teils bei > 4 ms). Wenn etwas in der Ausgabe Rot ist heißt das, dass das Ergebnis unmöglich ist (z.B. 10 Zahlen jeweils größer als 5 mit der Summe 20) oder nicht genügend Rechenzeit verteilt wurde.
    Bei der "Zufälligkeit" von nichtdoppelten Zahlen gibts aber ein wichtiges Problem zu beachten. Wenn [Anzahl Zahlen] * [Mindestwert] in etwa im Bereich der [Summe] liegt existiert keine zufälligkeit. Extremfall ist z.B. 2,3,4. 3 Zahlen mit der Summe 9. Dafür gibt es nur eine Lösung wenn doppelte verboten sind -> Kein Zufall !

    Spoiler anzeigen
    [autoit]

    ConsoleWrite(@CRLF)
    For $i = 0 To 9 Step 1
    Test(Random(1, 7, 1), Random(80, 150, 1), Random(5, 10, 1))
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Func Test($iMin, $iSum, $nCount, $iCalcTime = 50)
    Local $a, $c, $e, $u
    $a = RandomN($iMin, $iSum, $nCount, $iCalcTime, False)
    $c = @extended
    $e = @error
    $u = UBound($a)
    ConsoleWrite(($e ? '!' : '+') & ' Benötigte Zeit: ' & Round($c, 0) & ' µs' & @CRLF & ($e ? '!' : '+') & ' Mindestwert: ' & $iMin & @CRLF & ($e ? '!' : '+') & ' Anzahl Zahlen: ' & UBound($a) & @CRLF & ($e ? '!' : '+') & ' Summe: ' & Sum($a) & ' (sollwert: ' & $iSum & ')' & @CRLF & ($e ? '!' : '+') & ' ')
    For $i = 0 To UBound($a) - 1 Step 1
    ConsoleWrite($a[$i] & ($i = $u - 1 ? '' : ','))
    Next
    ConsoleWrite(@CRLF & @CRLF)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; ------------------------------------------------------------------------------------------------------------------------------------------------
    ; iMin - Mindestwert (dieser Wert wird bei den ausgegebenen Zahlen nicht unterschritten)
    ; iSum - Summe aller Zufallszahlen
    ; nCount - Anzahl der Zufallszahlen
    ; iCalcTime - Gestattete Rechenzeit (im Prinzip nur vorhanden, damit es sich nicht festfrisst falls ein unmögliches Ergebnis verlangt wird) MILLIsekunden !
    ; bMulti - True - Mehrfaches Vorkommen von Zahlen ist erlaubt
    ; | False - Mehrfaches Vorkommen ist verboten
    ; @error - 0 - Alles ok
    ; | 1 - Es konnte kein Ergebnis gefunden werden. Das kann entweder daran liegen,
    ; dass die Anzahl Runden unzureichend war (einfach runden erhöhen), oder
    ; das geforderte Ergebnis ist unmöglich. z.B. 10 Zahlen mit der Mindestgröße
    ; 5 die eine Summe von 20 ergeben. -> In dem Fall überlegen was man will.
    ; @extended - Beinhaltet grundsätzlich die benötigte Rechenzeit in µs (obacht, KEINE Millisekunden)
    ; ------------------------------------------------------------------------------------------------------------------------------------------------
    Func RandomN($iMin, $iSum, $nCount, $iCalcTime = 5, $bMultiple = False)
    Local $t = TimerInit(), $aRND[$nCount], $r, $nTMP, $s
    For $i = 0 To $nCount - 1 Step 1
    $aRND[$i] = $iSum
    Next
    $s = Sum($aRND)
    If $bMultiple = True Then
    While $s <> $iSum And TimerDiff($t) < $iCalcTime
    $r = Random(0, $nCount - 1, 1)
    If $s < $iSum Then
    $aRND[$r] = Round($aRND[$r] * Random(1, 2), 0)
    Else
    $nTMP = Round($aRND[$r] / Random(1, 2), 0)
    If $nTMP > $iMin Then $aRND[$r] = $nTMP
    EndIf
    $s = Sum($aRND)
    WEnd
    Else
    While $s <> $iSum And TimerDiff($t) < $iCalcTime
    $r = Random(0, $nCount - 1, 1)
    If $s < $iSum Then
    $nTMP = Round($aRND[$r] * Random(1, 2), 0)
    If Not Contains($aRND, $nTMP) Then $aRND[$r] = $nTMP
    Else
    $nTMP = Round($aRND[$r] / Random(1, 2), 0)
    If $nTMP > $iMin And Not Contains($aRND, $nTMP) Then $aRND[$r] = $nTMP
    EndIf
    $s = Sum($aRND)
    WEnd
    EndIf
    If $s = $iSum Then Return SetExtended(Int(TimerDiff($t)*1000), $aRND)
    Return SetError(1, Int(TimerDiff($t)*1000), $aRND)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Contains($a, $n)
    For $i = 0 To UBound($a) - 1 Step 1
    If $a[$i] = $n Then Return True
    Next
    Return False
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Sum($a)
    If Not IsArray($a) Then Return $a
    Local $s = $a[0]
    For $i = 1 To UBound($a) - 1 Step 1
    $s += $a[$i]
    Next
    Return $s
    EndFunc

    [/autoit]


    Edit: Hier nochmal die Verteilung für Min = 1, Sum = 250, Anzahl = 20
    [Blockierte Grafik: http://i.imgur.com/IfnGABU.png]
    Sieht eigentlich ganz passabel aus finde ich...

  • Hallo, das Problem ließe sich in viele Richtungen lösen, jedoch sind nicht alle geeignet da sich die Wahrscheinlichkeit dass bestimmte Zahlen getroffen werden bei jedem Algorithmus unterscheidet. Die Schwierigkeit ist es, einen Algorithmus zu finden, der (wie beim echten Zufall) die Wahrscheinlichkeiten nicht verändert. Wer viel Zeit hat, kann sich ja mal im nachfolgenden die Theorie dazu durchlesen, ich versuche mal zu erklären wo genau das Problem liegt und wie man es lösen kann. ^^

    Gehen wir mal davon aus dass du die Summe 6 mit 2 Würfeln treffen möchtest. Jeder Würfel hat einen Wertbereich von 1 bis 4. So lässt sich das im Folgenden besser erklären.

    Bei einem normalen Würfelwurf ist der Würfel eigentlich unabhängig von den anderen Würfeln. Das bedeutet, dass die Wahrscheinlichkeit für jede Seite des Würfels gleich ist getroffen zu werden. Sobald man aber auf eine bestimmte Summe hinaus spielt, verändern sich die Wahrscheinlichkeiten. Nun kommen nämlich die Variationen (nicht zu verwechseln mit den Kombinationen) ins Spiel, die alles so fürchterlich kompliziert machen. Weshalb Variationen? Ganz einfach, bei 2 Würfel mit jeweils 4 Augen können insgesamt 4² (also 16) mögliche Augenpaare getroffen werden. Aber nicht jedes Augenpaar entspricht der Summe 6. Siehe hier eine Liste:

    Man sieht eindeutig, dass es Unterschiede gibt dass eine bestimmte Summe getroffen wird. Das liegt daran, dass auch die Anordnung der Würfel berücksichtigt werden muss. Wir haben also einen Summen-Bereich von 2 bis 8 vorliegen. Die Wahrscheinlichkeit eine bestimmte Summe zu treffen variiert also. Hier wieder eine Liste mit den Wahrscheinlichkeiten:

    Code
    2 ->  1 von 16
    3 ->  2 von 16
    4 ->  3 von 16
    5 ->  4 von 16
    6 ->  3 von 16
    7 ->  2 von 16
    8 ->  1 von 16

    Jetzt könnten wir natürlich solange neu würfeln lassen, bis wir die passende Summe erwischt haben, aber das kann je nach Summe und Anzahl der Würfel extrem lange dauern. Daher müssen wir nicht die Augenzahlen der Würfel zufällig bestimmen, sondern die Variationen. In diesem Beispiel sind also nur die Variationen (2|4) (3|3) (4|2) zulässig. Wenn wir diese in einem Array abspeichern, können wir also die Zufallszahlen anhand der Variation bestimmen und kämen auf jeden Fall auf unsere Summe.

    [autoit]

    Dim $aArr[3][2] = [[2, 4], [3, 3], [4, 2]]
    Dim $iRnd = Random(0, 2, 1)

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite(' ' & $aArr[$iRnd][0] & ' + ' & $aArr[$iRnd][1] & ' = 6' & @CRLF)

    [/autoit]


    Nun zu dem eigentlichen Problem, wir haben ja die Summe 50 und 8 Würfel. Der Wertbereich der Würfel soll zwischen 1 und 50 liegen. Das bedeutet dass wir nun alle Variationen erst einmal ermitteln müssen. Dazu hatte ich mal ein Thread aufgemacht wo eine durchaus brauchbare Funktion raussprang. Siehe mal hier: Kombinationen ermitteln

    Und hier das Skript von Mars:

    [autoit]

    #include <Array.au3>

    [/autoit][autoit][/autoit][autoit]

    Global $a = _Calc(7, 4)
    _ArrayDisplay($a)

    [/autoit][autoit][/autoit][autoit]

    Func _Calc($nErg, $iCnt)
    Local $aRet[0][$iCnt], $u, $aCnt[$iCnt], $iPos = $iCnt - 1
    Local $iSum
    For $i = 0 To $iCnt - 1 Step 1
    $aCnt[$i] = 1
    Next
    Do
    $iSum = 0
    For $i = 0 To $iCnt - 1 Step 1
    $iSum += $aCnt[$i]
    Next
    If $iSum = $nErg Then
    $u = UBound($aRet)
    ReDim $aRet[$u+1][$iCnt]
    For $i = 0 To $iCnt - 1 Step 1
    $aRet[$u][$i] = $aCnt[$i]
    Next
    EndIf
    Until Not _Array($iCnt, $aCnt, $iPos, $nErg)
    Return $aRet
    EndFunc ;==>_Calc

    [/autoit][autoit][/autoit][autoit]

    Func _Array(ByRef $iCnt, ByRef $aCnt, ByRef $iPos, $nErg)
    $aCnt[$iPos] += 1
    If $aCnt[$iPos] = $nErg And $iPos > 0 Then
    $aCnt[$iPos] = 1
    $iPos -= 1
    _Array($iCnt, $aCnt, $iPos, $nErg)
    $iPos += 1
    EndIf
    If $aCnt[0] = $nErg Then Return False
    Return True
    EndFunc ;==>_Array

    [/autoit]


    Das müsste allerdings noch optimiert werden da dein Ergebnisraum zu groß ist. Das mache ich noch, aber nicht heute. Nur mal dass man ein Ansatz hat und die Wahrscheinlichkeit für jedes Ergebnis (wie bei einem Würfelwurf) auch gleich ist.

    Achja, falls das irgendwer schon in seinem Skript umgesetzt hat, ich habe mir nicht alles durchgelesen. ^^
    Steinigt mich ansonsten. LG. Make :)

  • ALLEN erst einmal meinen Dank !!! :*

    Entschieden habe ich mich für AspirinJunkie Lösung.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Die Zahlen sind zwar doof verteilt aber zufällig und in ihrer Summe immer 50:

    :D
    Die (ersten 2-3) Zahlen sind (meistens) zwar (innerhalb der mathematischen Grenzen) zufällig, aber doof verteilt und in ihrer Summe immer 50. Vier bis fünf Einsen sind nicht ungewöhnlich!

    Imho ist die Fragestellung bzw. die Anforderung schon gelinde gesagt fragwürdig!
    Wie AspirinJunkie in seinem Script deutlich gezeigt hat! (Ich denke, das war deine Absicht, du Fuchs :thumbup: )
    Man könnte mit minimalem Aufwand die Doppelten nicht zulassen, am Ergebnis würde sich nicht viel ändern!


    ...Script...Das müsste allerdings noch optimiert werden da dein Ergebnisraum zu groß ist.

    Der "Ergebnisraum" ist nicht zu groß, sondern aufgrund der Aufgabenstellung viel zu klein, s.o.


    @Alina, woher kommt diese Aufgabenstellung?

  • Wie AspirinJunkie in seinem Script deutlich gezeigt hat! (Ich denke, das war deine Absicht, du Fuchs )

    Nö.
    Eigentlich hatte ich bloß gerade mal kurz Zeit und hab da schnell ein Skript geschrieben.
    Dass die Verteilung sich Richtung der kleineren Werte verschiebt war zwar klar aber so langweilig habe ich es dann auch nicht erwartet.

    Mars' Grafik hat es dann aber sehr schön gezeigt wie die Verteilung tatsächlich aussieht.

  • Alina, ich verstehe dich nicht. Du möchtest "Zufällige" Zahlen. Ich hab natürlich nichts gegen AspirinJunkie, aber seine Funktion liefert im Regelfall hauptsächlich Einsen, das hat doch nix mit Zufällen zu tun.
    Dann wurde nie wirklich gesagt ob Zahlen nun einzeln, oder auch mehrfach vorkommen sollen. Wir haben hier einige interessante Beiträge mit einigen interessanten resultierenden Verteilungen gefunden. (Falls ich etwas vergessen habe bitte schreit mich an, Die BF Methode hab ich absichtlich nicht 10.000x laufen lassen, hab keine Jahrzehnte Zeit :P)

    Singe = Jede Zahl darf nur 1x vorkommen
    Multi = Jede Zahl darf beliebig oft vorkommen
    Micha_he - Der einzige der ne anständige (fast echte) Normalverteilung herzaubert (ist bei der Methode auch logisch)
    Chesstiger - Hier bekommt der "Zufall" direkt noch eine Packung Kreativität verabreicht :D
    AspirinJunkie - Klassischer Fall von 1/x² (oder sowas ähnliches)
    Mars (Single) - Sieht für mich nach einer halbwegs gelungenen halben Normalverteilung aus. (ich glaube, dass diese Verteilung charakteristisch für das gegebene Problem ist)
    Mars (Multi) - Auch irgendeine e Funktion

    Überlege mal welche Anforderungen du an die Verteilung stellst. Vorallem das mit den Doppelten und der verlangten "Zufälligkeit" ist interessant. Beispielsweise geben Micha_he und Chesstiger hauptsächlich 5,6,7,8,9,10,11 aus. Chesstiger hat es geschafft in diesem Bereich eine (bis auf den Zacken) Gleichverteilung hinzubekommen, Micha_he eine Normalverteilung gebastelt. AspirinJunkie's Methode liefert abfallende Zahlen mit fast 50% Einsen (im schnitt nach 10.000 Versuchen).
    [Blockierte Grafik: http://i.imgur.com/ixD9EOC.png]

  • Andy: Woher kommt diese Aufgabenstellung?
    Es ist einfach ein Spiel. Ich brauche dazu acht zufällige Zahlen. Vier davon waagerecht und vier senkrecht.

    Als nächste Schritt kommt:
    $Input9 = $Input1 + $Input5
    $Input10 = $Input2 + $Input5
    $Input11= $Input3 + $Input5
    $$Input2 = $Input3 + $Input5

    $Input13 = $Input1 + $Input6
    $Input14 = $Input2 + $Input6
    $Input15= $Input3 + $Input6
    $Input16= $Input3 + $Input7

    usw. Also es werden aus den waagerechten und senkrechten Zahlen die Zahlen Input9 bis Input 24 berechtigt.

    Sind diese Berechnungen durchgeführt, bekommt man vier Aufgaben, nämlich:
    - Klicke eine der errechneten Zahlen an.
    Wurde z. B. $Input14 angeklickt, so sollen dann $Input 10, 18, 22 (senkrecht) und $Input 13,15,16 ausgeblendet werden.
    Das ganze macht man vier mal insgesamt, wobei beim letzten mal eh nur noch eine Zahl über ist.
    Nimmt man nun alle die angeklickten Zahlen und addiert diese, ist es egal welche Zufallszahlen man angeklickt hat, es kommt immer was raus? :rock:

    Es ist eigentlich nur ein SPASS und ich habe das mal bei Youtube irgendwo gesehen. Und was da funktioniert und auch auf dem Papier, funktioniert dann auch mit AutoIt.

    50_pic = so soll die GUI aussehen
    50_pic_nach_berechnung = Werte sind berechnet (hier fest eingegebene Zahlen zur Demo.)
    50_pic_nach_viererauswahl = Demo wie es später sein soll.

    Und eine andere Berechnungsfunktion sehe ich später pos. entgegen, aber erst einmal soll es laufen.

    GUI:

    Spoiler anzeigen
    [autoit]


    $Form1_1 = GUICreate("50", 248, 226, 298, 237)
    $Input1 = GUICtrlCreateInput("Input1", 56, 8, 41, 21)
    $Input2 = GUICtrlCreateInput("Input2", 104, 8, 41, 21)
    $Input3 = GUICtrlCreateInput("Input3", 152, 8, 41, 21)
    $Input4 = GUICtrlCreateInput("Input4", 200, 8, 41, 21)
    $Input5 = GUICtrlCreateInput("Input5", 8, 32, 41, 21)
    $Input6 = GUICtrlCreateInput("Input6", 8, 56, 41, 21)
    $Input7 = GUICtrlCreateInput("Input7", 8, 80, 41, 21)
    $Input8 = GUICtrlCreateInput("Input8", 8, 104, 41, 21)
    $Input9 = GUICtrlCreateInput("Input9", 56, 32, 41, 21)
    $Input10 = GUICtrlCreateInput("Input10", 104, 32, 41, 21)
    $Input11 = GUICtrlCreateInput("Input11", 152, 32, 41, 21)
    $Input12 = GUICtrlCreateInput("Input12", 200, 32, 41, 21)
    $Input13 = GUICtrlCreateInput("Input13", 56, 56, 41, 21)
    $Input14 = GUICtrlCreateInput("Input14", 104, 56, 41, 21)
    $Input15 = GUICtrlCreateInput("Input15", 152, 56, 41, 21)
    $Input16 = GUICtrlCreateInput("Input16", 200, 56, 41, 21)
    $Input17 = GUICtrlCreateInput("Input17", 56, 80, 41, 21)
    $Input18 = GUICtrlCreateInput("Input18", 104, 80, 41, 21)
    $Input19 = GUICtrlCreateInput("Input19", 152, 80, 41, 21)
    $Input20 = GUICtrlCreateInput("Input20", 200, 80, 41, 21)
    $Input21 = GUICtrlCreateInput("Input21", 56, 104, 41, 21)
    $Input22 = GUICtrlCreateInput("Input22", 104, 104, 41, 21)
    $Input23 = GUICtrlCreateInput("Input23", 152, 104, 41, 21)
    $Input24 = GUICtrlCreateInput("Input24", 200, 104, 41, 21)
    GUISetState(@SW_SHOW)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    EndSwitch
    WEnd

    [/autoit]

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Ich will meine Version einfach auch mal posten:

    [autoit]


    Global $aZahlen = FillArray()

    [/autoit][autoit][/autoit][autoit]

    Global $iSumme = 0
    For $i = 0 To UBound($aZahlen) - 1
    ConsoleWrite($aZahlen[$i] & @CRLF)
    $iSumme += $aZahlen[$i]
    Next
    ConsoleWrite("Summe = " & $iSumme & @CRLF)

    [/autoit][autoit][/autoit][autoit]

    Func FillArray($iZahlen = 8, $iMax = 50)
    Local $aZahlen[$iZahlen], $iSumme = Random(1, Int(($iMax - $iZahlen) / $iZahlen), 1), $i = 1
    $aZahlen[0] = $iSumme
    Do
    $r = Random(1, Int(($iMax - $iSumme - $i) / 2) < 2 ? 2 : Int(($iMax - $iSumme - $i) / 2), 1)
    If $r + $iSumme < $iMax Then
    $iSumme += $r
    $aZahlen[$i] = $r
    $i += 1
    EndIf
    Until $i = $iZahlen
    If $iMax - $iSumme Then $aZahlen[Random(0, $iZahlen - 1, 1)] += $iMax - $iSumme
    Return $aZahlen
    EndFunc

    [/autoit]

    Keine Ahnung wie die Normalverteilung aussieht.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯