"Minimalisten"-Contest

    • Offizieller Beitrag

    Hi,
    wir hatten ja schon mal einen kleinen Programmierwettbewerb.
    In dieser Richtung möchte ich nochmal einen kleinen Vergleich anschieben - und zwar für alle Skriptpuristen.
    - Lösen einer Aufgabenstellung mit so wenig wie möglich Codezeilen

    Da ich gerade überlegt habe, wo noch weitere Tutorials sinnvoll sind, ist mir ins Auge gefallen, dass etliche codesparende Funktionen fast nie zum Einsatz kommen.
    Auf diese Art und Weise können wir hier mal ein paar Anregungen vermitteln.

    Also hier eine ganz schlichte Aufgabe, die auch von jedem innerhalb kürzester Zeit realisiert werden kann. Aber trotzdem bietet sie Einsparpotential:

    Zitat

    Simuliere die Ziehung der Lottozahlen 6 aus 49 (plus Zusatzzahl) und gib das Ergebnis nach der Ziehung gemeinsam aus (sortierte Ausgabe nicht erforderlich).
    Es kann alles verwendet werden, was die Version 3.2.10 bietet.

    Falls ihr Lust habt, schickt doch einfach eure Lösungen an mich per PN. Als Termin würd ich mal das WE, also den 26.01.08 bis Mitternacht setzen. Dann kann ich die Ergebnisse am Sonntag präsentieren.

    Mir geht es nicht vordergründig darum zu bewerten und einen Sieger zu küren, sondern ich bin an einer Vielzahl von Lösungswegen interessiert.
    Letztlich hoffe ich, dass ihr daraus Anregung für eure eigenen Projekte schöpfen könnt.


    EDIT:
    Nachdem einige Lösungen eingegangen sind, scheint es doch sinnvoll die Lottoregeln zu erklären:
    1. Aus den Zahlen 1 bis 49 werden 6 Zahlen gezogen.
    2. Aus den verbleibenden 43 Zahlen wird eine als Zusatzzahl gezogen.

  • Zitat

    Es kann alles verwendet werden, was die Version 3.2.10 bietet.

    Dann müssten doch auch includes auch erlaubt sein, oder?

    Mfg
    Jens (McPoldy)

    Twitter: jkroeger

    Denn die Dinge, die wir erst lernen müssen, bevor wir sie tun, lernen wir beim Tun.(Aristoteles)

    • Offizieller Beitrag

    Hi,

    ja schon, aber ich würde sagen, dass du die benötigten Funktionen aus den includes rauskopierst und dir somit das include sparst. Dann ist der Code und die Anzahl Zeilen usw. gleich ersichtlich. Ansonsten mache ich eine Datei, die alles macht und im Skript nur nach include + Ergebnisanzeige. :D

    Mega

  • :D kannst Du machen, wenn du mir zeigst das es bei der Installation von AutoIT im Include Verzeichnis vorhanden war ;)

    Nachtrag, habe jetzt auch noch eine ohne Include eingereicht, is glaub ich sogar noch weniger q-text :)

    Mfg
    Jens (McPoldy)

    Twitter: jkroeger

    Denn die Dinge, die wir erst lernen müssen, bevor wir sie tun, lernen wir beim Tun.(Aristoteles)

    Einmal editiert, zuletzt von McPoldy (21. Januar 2008 um 15:50)

    • Offizieller Beitrag

    Naja, ich werde es einfach so machen, dass ich die Codezeilenzahl und Skriptgröße einfach nebeneinanderstelle - dann könnt ihr das selbst werten. :)

    Ein echter Vergleich wird sowieso nicht möglich sein - dann müßte man auch Performance berücksichtigen, und das läßt sich schlecht prüfen.

    • Offizieller Beitrag

    Hier nun das Ergebnis.
    Ich habe die Lösungen nach Größe sortiert eingestellt.
    Die geringste Größe und dazu noch eine sehr interessante Lösung präsentiert Oscar. Da kann man nur sagen: :thumbup:
    Die wenigsten Zeilen hat Xenobiologist benötigt.

    Für mich etwas überraschend, dass es keine absolut identischen Lösungswege gab. Womit wieder mal bewiesen ist: Viele Wege führen nach Rom. :rolleyes:

    Oscar 7 Zeilen 300 Byte
    [autoit]


    Global $z, $t=' 01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849'
    For $i=0 TO 6
    $r = Random(1,49-$i,1)*2
    $z &= StringMid($t,$r,2) & StringLeft(' | ', 2+($i=5)*4)
    $t = StringMid($t,1,$r-1)& StringMid($t,$r+2)
    Next
    MsgBox(0,'',$z)

    [/autoit]
    progandy 10 Zeilen 342 Byte
    [autoit]


    Dim $s
    For $i=0 To 6
    Do
    $u=1
    $t=Random(1,49,1)
    If StringInStr($s,"|"&$t&"|") Then $u=0
    Until $u
    $s&=(($i==6)&"|"&$t&"|")
    Next
    MsgBox(0,"Lotto-Zahlen","6 aus 49: "&Stringregexpreplace(Stringregexpreplace($s,"(\|?False\|)"," "),"(\|True.*)","")&@CRLF&"Superzahl: "&Stringregexpreplace(StringTrimRight($s,1),"(.*True\|)",""))

    [/autoit]
    GtaSpider 16 Zeilen 343 Byte
    [autoit]


    MsgBox(0, '', _Lotto())
    Func _Lotto()
    Local $a[49],$sR,$sT,$rnd
    For $i=1 To 49
    $a[$i-1]=$i
    Next
    Do
    $i+=Assign("rnd",Random(0,48))
    $sR&=$a[$rnd]&","
    $a[$rnd]=''
    Until $i>55
    While $sT=''
    $sT=$a[Random(0,48)]
    WEnd
    Return StringTrimRight($sR,1)&"|"&$sT
    EndFunc

    [/autoit]
    BugFix 12 Zeilen 350 Byte
    [autoit]


    Global $a[7] = [0,0,0,0,0,0,0]
    Do
    $x = Random(1,49,1)
    For $i = 0 To UBound($a) -1
    If $a[$i] > 0 And $a[$i] = $x Then ExitLoop
    If $a[$i] = 0 Then
    $a[$i] = $x
    ExitLoop
    EndIf
    Next
    Until $a[UBound($a)-1] <> 0
    MsgBox(0, 'Lottozahlen', $a[0] & ' ' & $a[1] & ' ' & $a[2] & ' ' & $a[3] & ' ' & $a[4] & ' ' & $a[5] & ' Z: ' & $a[6])

    [/autoit]
    Xenobiologist 6 Zeilen 374 Byte
    [autoit]


    Global $z = ' ', $n = ''
    Do
    $n = Random(1, 49, 1)
    If Not StringRegExp($z, '(?<= )' & $n & '(?= )') Then $z &= $n & ' '
    Until StringInStr($z, ' ', 0, 8)
    MsgBox(64, 'Lotto (Mega)', 'Lottoziehung ' & @TAB & ':' & StringTrimRight($z, 3) & @CRLF & 'Zusatzzahl ' & @TAB & ': ' & StringRight($z, 3) & @CRLF & 'Superzahl' & @TAB & @TAB & ': ' & Random(1, 9, 1) & @CRLF)

    [/autoit]
    McPoldy 9 Zeilen 495 Byte
    [autoit]


    Dim $result
    For $i = 1 to 7
    Do
    $zahl = "," & Random(1,49,1) & ","
    Until StringInStr($result,$zahl) = 0
    $result &= StringRight($zahl,stringlen($zahl)-1)
    Next
    $result = StringSplit($result,",")
    MsgBox(64,"6 aus 49 plus Zusatzzahl","Zahl 1: " & $result[1] & @CRLF & "Zahl 2: " & $result[2] & @CRLF & "Zahl 3: " & $result[3] & @CRLF & "Zahl 4: " & $result[4] & @CRLF & "Zahl 5: " & $result[5] & @CRLF & "Zahl 6: " & $result[6] & @CRLF & "Zusatzzahl: " & $result[7])

    [/autoit]
    BugFix 2. 11 Zeilen 707 Byte
    [autoit]


    Global $str = '', $n = 0, $sum = 0, $a[49] = [1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184,34359738368,68719476736,137438953472,274877906944,549755813888,1099511627776,2199023255552,4398046511104,8796093022208,17592186044416,35184372088832,70368744177664,140737488355328,281474976710656]
    Do
    $r = Random(0,48,1)
    If Not BitAND($sum,$a[$r]) Then
    $sum = BitOR($sum, $a[$r])
    If $n < 6 Then $str &= $r+1 & ' '
    If $n = 6 Then $str &= ' Z: ' & $r+1
    $n += 1
    EndIf
    Until $n = 7
    MsgBox(0, 'Lottozahlen',$str)

    [/autoit]
    PhilRip * Zeilen und Größe wg. Include nicht feststellbar
    [autoit]


    #include <array.au3>
    Dim $lotto[7]
    For $i=0 to 5
    $ran=Random(1,49,1)
    If _ArraySearch($lotto, $ran)=1 Then
    $i-=1
    Else
    $lotto[$i]=$ran
    EndIf
    Next
    $lotto[6]=Random(1,9,1) ; Superzahl
    _ArrayDisplay($lotto)

    [/autoit]
    • Offizieller Beitrag

    Ich finde die Ergebnisse auch sehr interessant. Ganz besonders, weil ich der Einzige bin, der die gezogene Zahl aus der Gesamtmenge der Zahlen (1...49) entfernt, statt bei jeder Zahl zu testen, ob sie bereits gezogen wurde.
    Und das überrascht mich dann doch ein wenig, weil meine Methode der 'realen' Ziehung (wie sie im TV zu sehen ist) sehr nahe kommt. Nicht, dass das etwas am Ergebnis verändert, aber es ist schon faszinierend, wie man das Problem angehen kann.

    GtaSpider : Dein Script liefert nicht immer ein richtiges Ergebnis.
    Screenshot:

    BugFix : Dein 2. Script finde ich cool. Zum Einen, weil es total ungewöhnlich ist, zum Anderen, weil es die Diskrepanz zwischen Zeilenanzahl und Bytelänge verdeutlicht.
    Wenn man die erste Zeile:

    [autoit]


    Global $str = '', $n = 0, $sum = 0, $a[49] = [1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184,34359738368,68719476736,137438953472,274877906944,549755813888,1099511627776,2199023255552,4398046511104,8796093022208,17592186044416,35184372088832,70368744177664,140737488355328,281474976710656]

    [/autoit]


    zu Ungunsten der Zeilenanzahl ändert:

    [autoit]


    Global $str = '', $n = 0, $sum = 0, $a[49], $i
    For $i = 0 To 48
    $a[$i] = 2^$i
    Next

    [/autoit]


    erhält man ein (Bytemäßig) deutlich kleineres (und IMHO auch besser lesbares) Script.

    Nichtsdestotrotz finde ich solche Contests spannend und sehr lehrreich. Können wir gerne fortsetzen. :)

    • Offizieller Beitrag

    Oscar
    Diese Variante hatte ich auch noch fertig, aber 3 Ergebnisse posten war mir zu fett ;)
    Sie unterscheidet sich aber trotzdem von deiner, weil ich nicht die Zahl selbst ermittle, sondern deren Speicherplatz.
    Ich stells mal rein, vielleicht gefällts dir :)

    Spoiler anzeigen
    [autoit]

    Global $str = '', $ar[49] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49]
    For $i = 1 To 7
    $x = Random(0, UBound($ar)-1, 1)
    If $i < 7 Then
    $str &= $i & '. = ' & $ar[$x] & @LF
    Else
    MsgBox(0, 'Lottozahlen', $str & 'Zusatzzahl = ' & $ar[$x])
    EndIf
    $ar[$x] = $ar[UBound($ar)-1]
    ReDim $ar[UBound($ar)-1]
    Next

    [/autoit]
    • Offizieller Beitrag

    Ich entere noch mal den Thread :P

    Ich hab mir überlegt, wie man denn eine echte Bewertung durchführen könnte.
    Meiner Meinung nach benötigt man dafür einen Benchmark-Test, um verwendete RAM-Größe, Prozessorlast und Programmlaufzeit zu messen. (Ich denke, diese 3 Kenngrößen geben den Erfolg eines Skripts am besten wieder)
    Den kleinsten ermittelten Wert aus allen Skripten würde ich als Bezugsnormal auf einen Wert von 100 setzen.
    Alle anderen werden dann in % von diesem Ergebnis berechnet - sind also dann z.B. 122 o.ä., auf jeden Fall größer ;)
    Im Idealfall wären also 300 Punkte zu erreichen. Dann hätte man eine echte Vergleichsgröße. Zumal diese 3 Kenngrößen sich gegenseitig beeinflussen und dadurch z.B. ein zwar größeres Skript letztendlich wieder durch bessere Performance ausgleichen könnte.

    Nun fehlt uns nur noch solch ein Benchmarktest.
    Vielleicht hat ja schon jemand 'ne passende Idee, wie man den umsetzen könnte um unsere Skripts damit zu testen.

    Aber natürlich möchte ich gern wissen, ob ihr dieser Methode zustimmen würdet.
    Also laßt mal eure Meinungen los 8)

    • Offizieller Beitrag

    Halte ich für etwas schwierig, das bei so kleinen Skripte sinnvoll zu messen. Da spielt so viel von Betriebssystemseite und anderen Rechnerbelastungen rein, dass das m.E. kaum objektiv sein kann.
    Dass man aber mehere Kategorien hat, finde ich nicht schlecht. Vllt. Variablen zählen oder Funktionsaufrufe oder was auch immer...

    peethebee

  • Naja also um die reine Geschwindigkeit eines Skriptes zu messen hab ich mir vor Ewigkeiten schon ein Skript geschrieben welches auch Rückschlüsse auf die Genauigkeit der Zeitmessung zulässt:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstants.au3>
    #Include <GuiListView.au3>

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

    #region Variablen definieren
    Global $ZeitErgebnisse = ObjCreate("System.Collections.ArrayList")
    If @error Then
    MsgBox(0,"", "Fehler bei der Objekt-Erstellung")
    Exit
    EndIf

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

    Global $TimerDiffTime
    Global $Name, $Zeitsumme, $Zeitquadratsumme, $ZeitPunkt, $Zeit, $TempArray[3], $N, $i
    Global $GUI, $ListView, $Button, $eins, $e, $RahmenZeit
    #endregion

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

    ;------------------------------------------------------------------------------------------
    ;Anzahl der Messdurchläufe angeben - je höher N umso genauer wird die gemessene Zeitangabe:
    Global $N = 100
    ;------------------------------------------------------------------------------------------

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

    #region Zeitaufwand der Methode bestimmen
    $Name = "Test"
    $Zeitquadratsumme = 0
    $Zeitsumme = 0
    SplashTextOn("Test der Methode:", @CRLF & $Name, 250, 60)

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

    For $i = 1 To $N
    $ZeitPunkt = TimerInit()

    ;---------Code-----------
    Local $a
    $a = 1
    ;------------------------
    $Zeit = TimerDiff($ZeitPunkt)

    if $i < 3 Then ContinueLoop
    $Zeitsumme += $Zeit
    $Zeitquadratsumme += $Zeit^2
    Next
    $TempArray[0] = $Name
    $TempArray[1] = $Zeitsumme / $N
    $TempArray[2] = Sqrt((($N * $Zeitquadratsumme) - ($Zeitsumme^2)) / ($N* ($N - 1)))
    $ZeitErgebnisse.add($TempArray)
    SplashOff()
    #endregion

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

    #region Auswerten und Vergleichen
    _ArrayListSort2Dim($ZeitErgebnisse, 1, 0)

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

    $eins = $ZeitErgebnisse.Item(0)

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

    $GUI = GUICreate("Ergebnisse", 633, 307, 193, 115)
    $ListView = GUICtrlCreateListView("Name|Zeit [ms]|Verhältnis|Standardabweichung [ms]|rel. Abweichung", 0, 0, 632, 265)
    $Button = GUICtrlCreateButton("O.K.", 240, 272, 121, 33, 0)

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

    _GUICtrlListView_SetColumnWidth($ListView, 0, 203)
    _GUICtrlListView_SetColumnWidth($ListView, 1, 100)
    _GUICtrlListView_SetColumnWidth($ListView, 2, 75)
    _GUICtrlListView_SetColumnWidth($ListView, 3, 150)
    _GUICtrlListView_SetColumnWidth($ListView, 4, 100)

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

    For $e In $ZeitErgebnisse
    GUICtrlCreateListViewItem($e[0] & '|' & Round($e[1], 3) & '|' & Round($e[1] / $eins[1], 1) & '|' & Round($e[2], 4) & '|' & Int(100 * $e[2] / $e[1]) & '%', $ListView)
    Next

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

    GUISetState(@SW_SHOW)

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

    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    Exit
    Case $Button
    Exit
    EndSwitch
    WEnd
    #endregion

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

    ;Sortiert eine ArrayList mit enthaltenem Array nach einem Index dieses Arrays im Selection-Sort-Algorithmus
    ;Author: [email='AspirinJunkie@german-nlite.de'][/email]
    Func _ArrayListSort2Dim(ByRef $ArrayList, $DimIndex, $Descending = 0)
    Local $minIndex[2], $SortValue

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

    If Not IsObj($ArrayList) Then Return SetError(1, 1, 0)
    If $ArrayList.count = 0 Then Return SetError(2, 2, 0)

    $SortValue = $ArrayList.Item (0)
    If UBound($SortValue) <= $DimIndex Then Return SetError(3, 3, 0)

    If $ArrayList.count < 2 Then Return SetError(4, 4, 0)

    For $i = 0 To $ArrayList.count - 1
    $SortValue = $ArrayList.Item ($i)
    $SortValue = $SortValue[$DimIndex]

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

    $minIndex[0] = $i
    $minIndex[1] = $SortValue

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

    For $e = $i + 1 To $ArrayList.count - 1
    $SortValue = $ArrayList.Item ($e)
    $SortValue = $SortValue[$DimIndex]

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

    If $SortValue < $minIndex[1] Then
    $minIndex[0] = $e
    $minIndex[1] = $SortValue
    EndIf
    Next

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

    If Not ($minIndex[0] = $i) Then
    $ArrayList.Insert ($i, $ArrayList.Item ($minIndex[0]))
    $ArrayList.Insert ($minIndex[0] + 1, $ArrayList.Item ($i + 1))
    $ArrayList.RemoveAt ($minIndex[0] + 2)
    $ArrayList.RemoveAt ($i + 1)
    EndIf
    Next
    If $Descending Then $ArrayList.Reverse
    Return 1
    EndFunc

    [/autoit]


    Um Skriptcode zu testen muss man diesen in der Region "Zeitaufwand der Methode bestimmen" beim kommentierten Abschnitt "--------Code------" eintragen.
    Dem ganzen kann dann mit der Variable $Name noch ein passender Titel verpasst werden.
    Will man mehrere Skripte testen und direkt vergleichen so muss man lediglich die Region "Zeitaufwand der Methode bestimmen" kopieren und dort das nächste Skript entsprechend eintragen.
    Bisschen merkwürdige Bedienung - war aber bisher nur für meine Zwecke gedacht.
    Ich denke damit kann man die Geschwindigkeiten recht objektiv, weil qualitativ bewertbar, vergleichen.

    • Offizieller Beitrag

    @pee
    Die Auswertung würde ja für alle Skripts auf demselben System laufen - insofern ist die Hardware völlig außen vor, da für alle identisch.
    Gerade die Skripte zeigten ja, dass ein (zeilenzahlmäßig) größeres Skript kleiner sein kann. Deshalb wollte ich eigentlich keine "zählbaren" Parameter anwenden, sondern lieber leistungsbezogene.

    AspirinJunkie
    Ist doch schon mal ein erster Punkt.
    Mal sehen, was wir noch alles zusammen bekommen.