Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Code Optimierung


jackle32 - Fr 28.03.14 20:39
Titel: Code Optimierung
Hallo zusammen,

ich arbeite gerade ein einem Programm, dass mir ausrechnet wie viele Möglichkeiten es gibt eine bestimmte Anzahl von Punkten beim Bowling zu erreichen.

Ich habe meine Code schon so weit mir möglich optimiert. Was jetzt noch die längste Zeit dauert ist folgende Funktion:


Delphi-Quelltext
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:
50:
51:
52:
53:
54:
function TMyThreadA.Auswertung(Feld: array of integer): integer;
var
  i: integer;
begin

  for i := 0 to 8 do
  begin
    if Feld[i*2] = 10 then
    begin
      if Feld[(i+1)*2] =10 then
      begin
        self.ergebnis[i] := Feld[i*2]+Feld[(i+1)*2]+Feld[(i+2)*2];
      end
      else if Feld[(i+1)*2+1]=10 then
      begin
        self.ergebnis[i] := Feld[i*2]+Feld[(i+1)*2+1];
      end
      else
      begin
        self.ergebnis[i] := Feld[i*2]+Feld[(i+1)*2]+Feld[(i+1)*2+1]
      end;
    end
    else if Feld[i*2+1] =10 then
    begin
      self.ergebnis[i] := Feld[i*2+1]+Feld[(i+1)*2];
    end
    else
    begin
      self.ergebnis[i] := Feld[i*2]+Feld[i*2+1];
    end;
  end;

  if Feld[18] = 10 then
  begin
    if ((Feld[20] = 10)and(Feld[19] <> 10)) then
    begin
      self.ergebnis[9] := Feld[18]+Feld[20];
    end
    else
    begin
      self.ergebnis[9] := Feld[18]+Feld[19]+Feld[20];
    end
  end
  else if Feld[19] = 10 then
  begin
    self.ergebnis[9] := Feld[19]+Feld[20];
  end
  else
  begin
    self.ergebnis[9] := Feld[18]+Feld[19];
  end;

  result :=  SumInt(self.ergebnis);
end;


Dabei wird ein Feldarray übergeben. Jedes Feld stellt eine Wurf/Kugel im Bowlingspiel dar. Auf Grund der Regeln dabei kann man die Punktzahl nicht so leicht mit einer Formel ausrechnen. (Ich habe zumindest keine gefunden.)

Die Frage wäre jetzt wie könnte ich diesen Code optimieren, damit dieser schneller laufen kann?
Der Punkt ist eben, dass diese Funktion einmal für jede Konstellation an Punkten in den Würfen aufgerufen wird. Das sind theoretisch 11 hoch 21 mal. (Praktisch sind es weniger aber immer noch sehr viele)

Bin für jeden Hinweis dankbar!

Gruß,
Jack


Xion - Sa 29.03.14 11:51

user profile iconjackle32 hat folgendes geschrieben Zum zitierten Posting springen:
Das sind theoretisch 11 hoch 21 mal. (Praktisch sind es weniger aber immer noch sehr viele)

Ich denke dein Ansatz kann so nicht klappen. Selbst wenn man mal 11^10 Möglichkeiten ansetzt, sind es schon...öh...ziemlich viele. Selbst wenn du 1.000.000 Möglichkeiten testen kannst pro Sekunde, dauert es dann immernoch 7 Stunden.
Es stellt sich auch die Frage, wie deine Ausgabe aussehen wird...weil wenn du dann 1Mio Möglichkeiten bekommst, wie du die vorgegebene Punktezahl erreichen kannst, dann hilft dir das doch auch nicht weiter, oder? ;)
Wenn du für jede Punktezahl die Anzahl der Möglichkeiten bestimmen willst, dann musst du dir doch einen mathematischen Ansatz überlegen. Denn selbst die noch so tolle Funktion kann dir keine 11^21 Möglichkeiten in einer vernünftigen (oder auch unvernünftigen :P ) Zeit testen.

Grundsätzliche Komplexitätsreduktion:
Es ist doch egal, in welcher Runde i welche Punktezahl angenommen wird. Die Reihenfolge spielt dabei keine Rolle. Beim Generieren deiner Möglichkeiten kannst du also so vorgehen, dass die Würfe zunehmend besser werden (da man jede Wurffolge so umsortieren kann, dass die beste zuletzt und die schlechteste zuerst kommt). An der unglaublichen Größenordnung des Suchraums ändert das aber nicht viel.
Ok, so ganz klappt das auch nicht wegen den Regeln für Strike und Spare. Da müsste man sich noch was einfallen lassen.

Performantere Tests:
Die einzelnen Würfe sind weitestgehend unabhängig voneinander.
Berechne erstmal die Punktezahl für alle Einzelwürfe und bestimme, wie hoch der Bonus bei einem Strike oder Spare davor aussähe. In etwa so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type TWurfData=record
points: integer; //punkte des Wurfs
strikeBonus: integer; //punkte, die ein strike davor als Bonus erhält
spareBonus: integer;  //punkte, die ein spare davor als Bonus erhält
isStrike: integer;    //0 oder 1, if-Tests nur einmal ausführen, isStrike[i]*strikeBonus[i+1] ergibt den Bonus
isSpare: integer;     //0 oder 1, if-Tests nur einmal ausführen
end;

Von diesen Records gibts nur vergleichsweise wenige, sagen wir mal 11^2.
Das selbe kannst du für den letzten Wurf machen, bei dem es offenbar eine Sonderregeln gibt. Nehmen wir mal an, das sind auch 11^2 viele.
Wenn man nun alle Reihenfolgen dieser Records bestimmt, kommt man wieder auf die 11^20 Möglichkeiten, es ist aber deutlich performanter, weil man nur ein paar Zahlen des Records addieren muss und die ganzen Sprünge (if-Zweige) wegfallen. Das ganze könnte man dann noch als Assembler reinhacken.
Bei der monströsen Anzahl an Möglichkeiten ist das aber auch keine große Hilfe (selbst wenn die Funktion Fakor 1Mio schneller laufen sollte hilft das nicht wirklich).

Branch & Bound:
Einfacher Ansatz: Wenn bereits die ersten x Array-Elemente mehr Punkte verursachen als du vorgegeben hast, dann brauchst du die letzten (n-x) Array-Elemente nicht mehr alle durchprobieren, das wird dann nichts mehr.


jackle32 - Sa 29.03.14 17:26

@Xion: Danke schon mal für die Antwort.

Hier noch ein paar Hintergrundinfos:

Es sind genau 5726805883325784576 Möglichkeiten (ca. Faktor 1300 kleiner als 11^21) (Ergibt sich aus den Bowlingregeln).

Hintergrund ist, das ich die Verteilung der möglichen Punktzahlen sehen möchte (die absolute Zahl ist nicht so wichtig). Und klar wirklich sinnvoll ist die Aufgabe nicht, aber eine schöne Aufgabe, wenn man wirklich mal versuchen will wie performant ein Sourcecode gestaltet werden kann.

Durch Rekursion und Multithreading habe ich die Performance schon von 4500 gültige Berechnungen auf ca. 9,5 Mio. pro Sekunde gesteigert. Leider würde die ganze Berechnung immer noch ca. 19800 Jahre dauern :( . Bis 14 Kugeln lässt es sich auch schon ganz gut rechnen (Dauert nur ca. 7 Tage :P ).

Den Ansatz mit den Records hab ich nicht wirklich verstanden. Kannst du dafür eine kurze Beispielrechnung machen, bitte?

Gruß,
Jack


Mathematiker - Sa 29.03.14 20:02

Hallo,
ich habe mir auch einmal ein paar Gedanken gemacht. Meine rekursive Lösung ist nicht elegant, aber funktioniert zumindest für eine kleine Anzahl von Würfen.
Allerdings fehlt noch die Spezialbehandlung eines evtl. Strikes im 10.Frame.


Delphi-Quelltext
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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
procedure TForm1.Berechnung(Sender: TObject);
var feld:array[0..300of integer;
    pu,nr,strikespare:integer;
    abbruch:integer;
    j:integer;
    t1x,t2x,frequenz : TLargeInteger;

procedure wurf(nr:integer;moeglich:integer;pu:integer;strikespare:integer);
var i,zusatz,doppelt:integer;
begin
    if nr>abbruch then
    begin
      inc(feld[pu]);
      exit
    end;

    for i:=0 to moeglich do
    begin
      if strikespare>0
      then
      begin
        zusatz:=i;
        doppelt:=0;
        if strikespare>2 then begin zusatz:=2*i; doppelt:=1 end;
        if odd(nr) then
        begin
          if i=moeglich then wurf(nr+2,10,pu+i+zusatz,strikespare+1-doppelt)
                        else wurf(nr+1,10-i,pu+i+zusatz,strikespare-1-doppelt)
        end
        else
        begin
          if i=moeglich then wurf(nr+1,10,pu+i+zusatz,strikespare-doppelt)
                        else wurf(nr+1,10,pu+i+zusatz,strikespare-1-doppelt)
        end;
      end
      else
      begin
        if odd(nr) then
        begin
          if i=moeglich then wurf(nr+2,10,pu+i,strikespare+2)
                        else wurf(nr+1,10-i,pu+i,strikespare)
        end
        else
        begin
          if i=moeglich then wurf(nr+1,10,pu+i,strikespare+1)
                        else wurf(nr+1,10,pu+i,strikespare)
        end;
      end;
    end
end;

begin
    nr:=1;
    pu:=0;
    strikespare:=0;
    listbox1.clear;
    fillchar(feld,sizeof(feld),0);
    abbruch:=10;
    QueryPerformanceFrequency (frequenz);      // Frequenz des Zählers
    QueryPerformanceCounter (t1x);       // Zählerstand 1
    wurf(nr,10,pu,strikespare);
    for j:=0 to 300 do
      listbox1.items.add(inttostr(j)+#9+inttostr(feld[j]));
    QueryPerformanceCounter (t2x);       // Zählerstand 2
    listbox1.items.insert(0,'Zeit '+FormatFloat('0.0 s',(t2x-t1x)/frequenz));
end;

Für 10 Würfe (5 Frames) braucht mein Rechner 9 s, 11 Würfe (96 s), d.h. für 14 Würfe etwa 60 Stunden. Das ist also auch noch viel zu langsam.
Übrigens werden die Datentypen integer/int64 wohl nicht reichen, um bei 10 Frames alle Möglichkeiten zu zählen.
Mal sehen, ob ich noch etwas beschleunigen kann.

Beste Grüße
Mathematiker

Nachtrag: Ich habe es noch einmal nicht rekursiv versucht, d.h. alle möglichen Spiele werden erzeugt und ausgewertet:

Delphi-Quelltext
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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
procedure TForm1.Berechnung2(Sender: TObject);
var anzahl : integer;
    moeglichkeiten : array[1..66of record a,b:integer end;
    i,j,nr:integer;
    zaehler : array[1..11of integer;
    feld:array[0..300of integer;
    t1x,t2x,frequenz : TLargeInteger;
procedure auswertung;
var summe,i,w1,w2:integer;
    strike:integer;
begin
    summe:=0;
    strike:=0;
    i:=1;
    repeat
      w1:=moeglichkeiten[zaehler[i]].a;
      w2:=moeglichkeiten[zaehler[i]].b;
      case strike of
        1,2 : begin summe:=summe+w1; dec(strike); end;
          3 : begin summe:=summe+2*w1; dec(strike,2); end;
      end;
      if w1<>10 then
        if strike>0 then begin summe:=summe+w2; dec(strike); end;

      if w1=10 then begin summe:=summe+10; inc(strike,2end
               else summe:=summe+w1;
      if w2>0 then
         if w2+w1=10 then begin summe:=summe+w2; inc(strike) end
                     else summe:=summe+w2;
        end;
      end;
      inc(i);
    until i>anzahl;
    inc(feld[summe]);
end;
begin
    QueryPerformanceFrequency (frequenz);      // Frequenz des Zählers
    QueryPerformanceCounter (t1x);       // Zählerstand 1
    listbox1.clear;
    fillchar(feld,sizeof(feld),0);
    nr:=1;
    for i:=0 to 10 do
      for j:=0 to 10-i do
      begin
        moeglichkeiten[nr].a:=i;
        moeglichkeiten[nr].b:=j;
        inc(nr);
      end;
    for i:=1 to 11 do zaehler[i]:=1;
    anzahl:=4;

    repeat
      auswertung;
      inc(zaehler[1]);
      if zaehler[1]>66
      then
      begin
        i:=1;
        while zaehler[i]>66 do
        begin
          zaehler[i]:=1;
          inc(zaehler[i+1]);
          inc(i);
        end;
      end;
    until zaehler[anzahl+1]>1;

    for j:=0 to 300 do
      listbox1.items.add(inttostr(j)+#9+inttostr(feld[j]));
    QueryPerformanceCounter (t2x);       // Zählerstand 2
    listbox1.items.insert(0,'Zeit '+FormatFloat('0.0 s',(t2x-t1x)/frequenz));

end;

Und das ist viel langsamer. Für 5 Frames braucht diese Lösung 36 s. Also viel schlechter.
Irgendwie komisch.


jackle32 - So 30.03.14 02:14

Hallo Mathematiker,

okay die Zahlen sind echt beeindruckend. Werde mir diesen Code später mal genauer anschauen. Damit wäre mein Algorithmus ja nochmal um den Faktor 14 schneller. :shock:

Was mich jetzt natürlich brennend interessieren würde wie deine Häufigkeitsverteilung aussieht (Zahlen) und wie viele Möglichkeiten du gefunden hast.
Könntest du mir bitte diese Zahle zukommen lassen, würde die dann mit meine Ergebnissen vergleichen.

Gruß,

Jack


Xion - So 30.03.14 02:18

user profile iconjackle32 hat folgendes geschrieben Zum zitierten Posting springen:
Durch Rekursion und Multithreading habe ich die Performance schon von 4500 gültige Berechnungen auf ca. 9,5 Mio. pro Sekunde gesteigert. Leider würde die ganze Berechnung immer noch ca. 19800 Jahre dauern :( . Bis 14 Kugeln lässt es sich auch schon ganz gut rechnen (Dauert nur ca. 7 Tage :P ).

Den Ansatz mit den Records hab ich nicht wirklich verstanden. Kannst du dafür eine kurze Beispielrechnung machen, bitte?


Ich wollte gerade mal ein Beispiel schreiben, hab aber gemerkt, dass es da noch ein paar Details zu beachten gibt (was auch daran liegt, dass ich keine Ahnung vom Bowling hab :P ). Allerdings lohnt es sich nicht wirklich, das nun auszuformulieren, weil es wohl kaum genug bringen wird, um die 20k Jahre auf einen vernünftigen Wert zu senken.
Die Idee ist prinzipiell, so viel wie möglich im voraus (einmal) zu berechnen und dann diese Ergebnisse wiederzuverwenden. Wenn du in deinem Fall ein Feld [4,4,4,4,4,4,4,1] hast, und als nächstes [4,4,4,4,4,4,4,2] ausrechnest, dann berechnest du alles neu, obwohl das garnicht nötig wäre.

Außerdem ist es immer gut, gleichwertige Lösungen schnell zu erkennen. z.B. gäbe [4,4,4,4,4,4,4,1] gleich viele Punkte wie [4,4,4,1,4,4,4,4]. Das sollte man beim Kandidatengenerieren schlau integrieren, damit man die Punktezahl nur einmal ausrechnen muss. Da du alle Möglichkeiten als Häufigkeiten bestimmen willst, muss man dann aber auch noch berechnen, wie viele das nun (ursprünglich) waren.

Es gibt übrigens auch noch andere Verfahren, relative Häufigkeiten zu bestimmen. Die banale Lösung wäre, man generiert sich mal 1.000.000 Möglichkeiten zufällig und wertet deren Punkte aus. Statistisch gesehen kriegt man dann schonmal eine Näherung der Verteilung. Wenn man etwas Sympathie zur Wahrscheinlichkeitsrechnung hat (was auf mich garnicht zutrifft), kann man dann sogar noch ausrechnen, wie weit man maximal daneben liegt. (z.B. nach Hoeffding [http://de.wikipedia.org/wiki/Hoeffding-Ungleichung])


Mathematiker - So 30.03.14 12:56

Hallo,
so das Problem ist vom Tisch! :dance2:
Mit meiner neuen Lösung braucht mein Rechner weniger als 100 ms für 10(!) Frames.

Achtung! Delphi-Quelltext weiter unten, da der hier fehlerhaft war.

Folgende Grundidee habe ich genutzt:
Da wir nicht wissen wollen, welche einzelnen Möglichkeiten für die 10 Frames auftreten, sondern nur die möglichen Punktzahlen benötigen, gehe ich portionsweise vor.
Zuerst berechne ich genau 1 Frame und speichere die möglichen Endzustände, d.h. die Punkte und evtl. noch wirkende Strikes und Spares.
Anschließend starte ich mit den 270 gespeicherten Zuständen und rechne jeweils wieder 1 Frame. Da ich weiß, wie viele Punkte am Start vorhanden waren und wie oft dieser Zustand auftrat, bekomme ich am Ende das Ergebnis nach 2 Frames.
Wiederhole ich dies noch 8 mal, habe ich alle 10 Frames berechnet.

Achtung! Das Ergebnis befindet sich in einem Beitrag weiter unten.

Und alles in gut 40 Millisekunden.
Auch ein Strike bzw. Spare im 10.Frame sind berücksichtigt.
Jetzt bin aber erst einmal stolz auf mich.

Beste Grüße
Mathematiker

Nachtrag: Fehler bei Strike im 10.Frame beseitigt. siehe weiter unten


Thorsten83 - So 30.03.14 13:39

Yay, dynamische Programmierung :) :) :)

Schöne Lösung!


Horst_H - So 30.03.14 16:13

Hallo,

Wunderbar gelöst, aber stoppst Du die Zeit für den Eintrag in die Listbox mit ;-)
Ich habe in der Konsole mit fpc 2.6.3 ( OK 2.6.4 ist aktuell) unter Linux laufen lassen und es braucht für 100 Durchläufe 1.1 Sekunden, also 11 ms :zustimm:
Übrigens: Summe 1.568.336.880.910.828.616
Die Idee einen Wurf mit allen Möglickeiten zu machen und eine Augensummenliste zu machen war mir auch gekommen.
Ähnlich dem Parallelverschieben des Wurfes in http://www.entwickler-ecke.de/viewtopic.php?t=112655 wäre es hier eine Addition der Augenzahlen und der dort eingetragenen absoluten Häufigkeit.Das wäre komplett ohne if.
Aber die letzten Würfe wäre etwas schwieriger.
Ich probiere das mal.

Gruß Horst


Mathematiker - So 30.03.14 16:44

Hallo,
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
... aber stoppst Du die Zeit für den Eintrag in die Listbox mit ;-)

Oh je, genau das mache ich. Die reine Berechnung liegt bei nur 3,0-3,1 ms.

Wenn man sich überlegt, dass am Anfang 19800 Jahre Rechenzeit veranschlagt wurden, so ist dies wieder ein schönes Beispiel dafür, dass eigentlich immer der Algorithmus über die Geschwindigkeit entscheidet. Mit einem neuen Verfahren verkürzt sich die Berechnungszeit um den Faktor 200 Billionen(!). Um das mit besserer Hardware zu erreichen, müssen viele, viele Generationen von PCs vergehen.

Auch meine Lösung hat noch einen Schwachpunkt. Mit etwas mehr Aufwand könnte ich die Rekursion noch vollkommen 'rauswerfen. Das dürfte noch etwas Zeitgewinn bringen. Mal sehen, was noch möglich ist.

Beste Grüße
Mathematiker


jackle32 - So 30.03.14 17:08

Ich bin beeindruckt!! :flehan: :flehan:

@Mathematiker:
Einen kleinen Makel hab ich aber doch noch. Bei deiner Berechnung gibt es keine Möglichkeit 299 Punkte zu erreichen, was natürlich beim Bowling möglich ist. Und zwar mit 20 Strikes und einer 9 am Schluss. Daher denke ich du beachtest den optionalen 3. Wurf im 10 Frame noch nicht.

Ansonsten bin ich aber tief beeindruckt.

Gruß,
Jack


Mathematiker - So 30.03.14 17:21

Hallo,
user profile iconjackle32 hat folgendes geschrieben Zum zitierten Posting springen:
Bei deiner Berechnung gibt es keine Möglichkeit 299 Punkte zu erreichen, was natürlich beim Bowling möglich ist. ...

Sorry, da ich kein Bowling-Spieler bin, habe ich wohl etwas falsch verstanden. :autsch:
Ich denke jetzt habe ich es aber richtig: (Das war ein Trugschluss, weiter unten ist es richtig.)

Achtung! Delphi-Quelltext weiter unten.

Beste Grüße
Mathematiker


Xion - So 30.03.14 17:28

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Mit einem neuen Verfahren verkürzt sich die Berechnungszeit um den Faktor 200 Billionen(!).

Richtig, insbesondere hast du die Komplexität des Lösungsverfahrens ganz wesentlich reduziert, wenn man mehr Würfe machen würde, käme also ein noch viel höherer Faktor raus.

Wenn ich da sehen muss, wie lange heutige Office-Pakete zum starten brauchen...das kommt halt dabei raus, wenn man ganz und gar auf die Effizienz des C++-Compilers vertraut und sich um die Algorithmen deswegen keine Gedanken mehr macht...


Horst_H - So 30.03.14 21:40

Hallo,

ich wollte mal einen einzelnen Wurf "sehen".
Also nur bis 30 und die Sonderregel für die letzten Würfe auskommentiert:

Delphi-Quelltext
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:
    for laeufe:=1 to 1 do
    begin
      feld2:=feld;
      fillchar(feld,sizeof(feld),0);
      for j:=0 to 30 do
        for m:=0 to 3 do
        begin
          if feld2[j,m]>0 then
          begin
            faktor:=feld2[j,m];
            summand:=j;
            nr:=1;
            pu:=0;
            strikespare:=m;
            wurf(nr,10,pu,strikespare);
          end;
        end;
    end;
{  Sonderbehandlung aus kommentiert
    feld2:=feld;
    for j:=0 to 270 do begin
...
        if feld2[j,1]>0 then //spare im 10.
        begin
          for i:=1 to 10 do inc(feld[j+i,0]);
        end;
      end;
    end;}

Das ergibt:

Quelltext
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:
0  1
1  4
2  10
3  20
4  35
5  56
6  84
7  120
8  165
9  220
10  286
11  328
12  370
13  384
14  398
15  380
16  362
17  308
18  254
19  160
20  66
21  50
22  57
23  40
24  48
25  30
26  39
27  20
28  30
29  10
30  21
Summe   4356

Wie kann 4 mal die 1 vorkommen?
http://de.wikipedia.org/wiki/Bowling ( Haus/Frame sind dort erklärt )
Es bei ersten Haus nur Frame1 = 0..1 und Frame2 = 1..0 sein also 2 Möglichkeiten.
Hier sieht es so aus, als würde das zweite Haus mit ein bezogen.
10 Möglichekten für 2 sehe ich auch nicht.
0/2 oder 1,1 oder 2/0 im ersten Haus.
Ich habe mal dies für die Augensumme eines Wurfes gepinselt:

Delphi-Quelltext
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:
procedure AugenSummeErstellen;
var
  Haus2Frame1,Haus2Frame2,Haus1Frame1,Haus1Frame2,i,
  iSum,jsum: LongWord;

begin
  Fillchar(AugenSumme,SizeOf(AugenSumme),#0);
  For Haus1Frame1 := 10 downto 0 do
    //Man kann nur die uebrigen wegkegeln
    For Haus1Frame2 := 10-Haus1Frame1 downto 0 do
    begin
      iSum := Haus1Frame1+Haus1Frame2;
      write(isum:4);
      IF iSum < 10 then
        inc(AugenSumme[iSum])
      else
      begin
        //ab hier muss isum = 10 sein
        For Haus2Frame1 := 10 downto 0 do
          For Haus2Frame2 := 10-Haus2Frame1 downto 0 do
          begin
            jSum := 10+Haus2Frame1+Haus2Frame2;
            //Strike
            IF Haus1Frame1 = 10 then
            begin
              //Keine 10 folgend
              IF jSum <20 then
                inc(AugenSumme[jsum])
              else
              begin
                 IF Haus2Frame1 = 10 then
                 Begin
                   For i := 0 to 10 do
                     inc(AugenSumme[jsum+i])
                 end
                 else
                   inc(AugenSumme[jsum]);
              end;
            end
            //Spare
            else
              inc(AugenSumme[jsum]);
          end;
        end;
      end;
      writeln;
end;

Da kommt so ein Unsinn raus, weil ich mich in den If verstrickt habe :-(

Quelltext
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:
    0                 1
   1                 2
   2                 3
   3                 4
   4                 5
   5                 6
   6                 7
   7                 8
   8                 9
   9                10
  10                11  // Haus1 = 10/Haus2 = 0 // 11 von 66 sind 10 
  11                22  // 11 x Anzahl Haus2=1 == Haus1= 1 also Faktor 2 
  12                33
  13                44
  14                55
  15                66
  16                77
  17                88
  18                99
  19               110
  20               121
  21                 1  //Haus1Frame1=Haus2Frame1= 10 
  22                 1
  23                 1
  24                 1
  25                 1
  26                 1
  27                 1
  28                 1
  29                 1
  30                 1


Ganz koscher ist mir die Sache noch nicht ;-)

Gruß Horst


Mathematiker - So 30.03.14 21:52

Hallo,
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
ich wollte mal einen einzelnen Wurf "sehen".
Also nur bis 30 und die Sonderregel für die letzten Würfe auskommentiert:

Delphi-Quelltext
1:
2:
    for laeufe:=1 to 1 do 
   ....

Hier sieht es so aus, als würde das zweite Haus mit ein bezogen.

Richtig. Du hast übersehen, dass die Schleife die Wiederholungen der Frame-Berechnung sind.
Vor

Delphi-Quelltext
1:
    for laeufe:=1 to 1 do ...                    

steht noch ein

Delphi-Quelltext
1:
    wurf(nr,10,pu,strikespare);                    

für den 1.Frame. D.h., möchtest Du nur den 1.Frame sehen, muss die Schleife vollkommen raus.
Einen einzelnen Wurf, also den 1.Teil eines Frames, kannst Du nur sehen, wenn Du die abbruch-Variable auf 1 setzt und natürlich die Schleife rausnimmst. Durch die Rekursion berechne ich bei Aufruf der wurf-Routine mit nr:=1 immer zwei Würfe, also einen Frame.

Natürlich können sich noch Fehler verstecken. Aber das Genannte müsste korrekt sein.

Beste Grüße
Mathematiker


jackle32 - Mo 31.03.14 20:50

Hallo zusammen,

ich sehe schon die Diskussionen gehen noch weiter ;).

Eine kleine Anmerkung/Frage hab ich noch. Ich finde den Code echt schnell und habe bis jetzt noch nicht wirklich verstanden wie der funktioniert :eyecrazy: :bawling: .

Was ich aber noch komisch finde, ist die Gesamtzahl der Möglichkeiten. Eigentlich sollten es, wie oben schon mal beschrieben, 572680588332578457 Möglichkeiten sein. Auf die Zahl komme ich durch eine Betrachtung der ersten Anzahlen an Möglichkeiten. Dabei ergibt sich eine Regel. Für jede erste Kugel im Frame muss die Anzahl mal 11 genommen werden und für jede zweite Kugel im Frame, ergibt sich auf Grund der Bowlingregeln, ein Faktor von 6. Im letzten Frame gibt es dann nochmal 241 Möglichkeiten.
So komme ich auf:

Möglichkeiten = 11^9*6^9*241

Bei dem vorher vorgestellten Code kommen aber "nur" 1568336880910855136 Möglichkeiten raus.

Mach ich da jetzt den Fehler oder ist der Code oben doch noch nicht ganz richtig? (Vermutung meinerseits ist, dass nicht alle Möglichkeiten im 10 Frame berücksichtigt werden)

@Horst_H: Für einen Wurf gibt es ja nur die Punktezahlen 0-10 und jede genau einmal. Also gibt es genau 11 Möglichkeiten. Oder verstehe ich da schon wieder was falsch?

Gruß,
Jack


Mathematiker - Mo 31.03.14 22:02

Hallo,
user profile iconjackle32 hat folgendes geschrieben Zum zitierten Posting springen:
Eigentlich sollten es, wie oben schon mal beschrieben, 572680588332578457 Möglichkeiten sein. ...Möglichkeiten = 11^9*6^9*241

Sorry, das stimmt nicht.
Im 10.Frame gibt es 55 Möglichkeiten Pins stehen zu lassen, ohne einen weiteren Wurf. 10 Möglichkeiten für einen Spare mit einem weiteren Wurf mit 11 möglichen Ausgängen. Der 1 Strike hat 2 Würfe zur Folge mit je 11 Ausgängen.
Damit gibt es im 10.Frame 55 + 10*11 + 1*11*11 = 286 Möglichkeiten und insgesamt für ein Bowling-Game

Quelltext
1:
Möglichkeiten = 11^9*6^9*286 = 6796126483946781696                    


Da ich in meinem Programm natürlich bei dieser Auswertung immer noch einen Fehler hatte, war das Ergebnis falsch.
Ich hatte vergessen, die Anzahl der möglichen Wege zu einem Spare/Strike im 10.Frame zu berücksichtigen.
Jetzt ist es aber richtig (hoffe ich :wink: ):


Delphi-Quelltext
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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
procedure TForm1.Berechnung(Sender: TObject);
var feld,feld2:array[0..300,0..3of int64;
    pu,nr,strikespare:integer;
    abbruch:integer;
    i,j,m:integer;
    faktor,summand,summe:int64;
    t1x,t2x,frequenz : TLargeInteger;
    laeufe:integer;
procedure wurf(nr:integer;moeglich:integer;pu:integer;strikespare:integer);
var i,zusatz,doppelt:integer;
begin
    if nr>abbruch then
    begin
      feld[pu+summand,strikespare]:=faktor+feld[pu+summand,strikespare];
      exit
    end;

    for i:=0 to moeglich do
    begin
      if strikespare>0
      then
      begin
        zusatz:=i;
        doppelt:=0;
        if strikespare>2 then begin zusatz:=2*i; doppelt:=1 end;
        if odd(nr) then
        begin
          if i=moeglich then wurf(nr+2,10,pu+i+zusatz,strikespare+1-doppelt)
                        else wurf(nr+1,10-i,pu+i+zusatz,strikespare-1-doppelt)
        end
        else
        begin
          if i=moeglich then wurf(nr+1,10,pu+i+zusatz,strikespare-doppelt)
                        else wurf(nr+1,10,pu+i+zusatz,strikespare-1-doppelt)
        end;
      end
      else
      begin
        if odd(nr) then
        begin
          if i=moeglich then wurf(nr+2,10,pu+i,strikespare+2)
                        else wurf(nr+1,10-i,pu+i,strikespare)
        end
        else
        begin
          if i=moeglich then wurf(nr+1,10,pu+i,strikespare+1)
                        else wurf(nr+1,10,pu+i,strikespare)
        end;
      end;
    end
end;
begin
    nr:=1;
    pu:=0;
    strikespare:=0;
    listbox1.clear;
    fillchar(feld,sizeof(feld),0);
    fillchar(feld2,sizeof(feld2),0);
    abbruch:=2;
    QueryPerformanceFrequency (frequenz);      // Frequenz des Zählers
    QueryPerformanceCounter (t1x);       // Zählerstand 1

    faktor:=1;
    summand:=0;
    wurf(nr,10,pu,strikespare);

    for laeufe:=1 to 9 do
    begin
      feld2:=feld;
      fillchar(feld,sizeof(feld),0);
      for j:=0 to 270 do
        for m:=0 to 3 do
        begin
          if feld2[j,m]>0 then
          begin
            faktor:=feld2[j,m];
            summand:=j;
            nr:=1;
            pu:=0;
            strikespare:=m;
            wurf(nr,10,pu,strikespare);
          end;
        end;
    end;

    feld2:=feld;
    for j:=0 to 270 do begin
      begin
        if (feld2[j,3]>0then //strike im 9. und 10.
        begin
          dec(feld[j,0],feld2[j,3]);
          for i:=0 to 10 do
            for m:=0 to 10 do begin
              inc(feld[j+m+2*i,0],feld2[j,3])
            end;
        end;
        if (feld2[j,2]>0then //strike im 10. nicht im 9.
        begin
          dec(feld[j,0],feld2[j,2]);
          for i:=0 to 10 do
            for m:=0 to 10 do begin
              inc(feld[j+m+i,0],feld2[j,2])
            end;
        end;
        if feld2[j,1]>0 then //spare im 10.
        begin
          dec(feld[j,0],feld2[j,1]);
          for i:=0 to 10 do inc(feld[j+i,0],feld2[j,1]);
        end;
      end;
    end;
    QueryPerformanceCounter (t2x);       // Zählerstand 2

    summe:=0;
    for j:=0 to 300 do
    begin
      listbox1.items.add(inttostr(j)+#9+inttostr(feld[j,0]+feld[j,1]+feld[j,2]+feld[j,3]));
      summe:=summe+feld[j,0]+feld[j,1]+feld[j,2]+feld[j,3];
    end;
    listbox1.items.insert(0,'Summe '+inttostr(summe));
    listbox1.items.insert(0,'Zeit '+FormatFloat('0.0 ms',1000*(t2x-t1x)/frequenz));
    listbox1.items.insert(0,'10 Frames');
    listbox1.items.savetofile('Lrekursiv.txt');
end;


mit dem Endergebnis


Quelltext
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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
10 Frames
Zeit 3,1 ms
Summe 6796126483946781696
0  1
1  20
2  210
3  1540
4  8855
5  42504
6  177100
7  657800
8  2220075
9  6906900
10  20030010
11  54627084
12  141116637
13  347336412
14  818558424
15  1854631380
16  4053948342
17  8574134256
18  17590903116
19  35084425512
20  68153183370
21  129156542048
22  239128282298
23  433093981988
24  768175041710
25  1335679120556
26  2278764602850
27  3817722438568
28  6285429080478
29  10176062216148
30  16210692174654
31  25423801988711
32  39275063100176
33  59790697496322
34  89738372684186
35  132838680323437
36  194014728204860
37  279679139693760
38  398054762537508
39  559521664930589
40  776978653753348
41  1066202799665260
42  1446185611494100
43  1939419976193134
44  2572108249645769
45  3374259457662750
46  4379642940349963
47  5625567357096640
48  7152458043083713
49  9003212336203823
50  11222321532368224
51  13854759161115192
52  16944647743901701
53  20533729301988559
54  24659677860186344
55  29354304148304945
56  34641713010992584
57  40536482068392501
58  47041935721268511
59  54148591515303027
60  61832856328337207
61  70056047874106382
62  78763812552417848
63  87886003727141549
64  97337074436149062
65  107017025187655349
66  116812929896943652
67  126601040952965360
68  136249447673994686
69  145621230941047405
70  154578023388704719
71  162983849241515226
72  170709088648566810
73  177634384171611642
74  183654297882070924
75  188680521351588656
76  192644465812746882
77  195499080514586477
78  197219810486845292
79  197804643162782380
80  197273281919910624
81  195665512419350681
82  193038919748521443
83  189466103203616503
84  185031613877402891
85  179828771486938774
86  173956578610064346
87  167516824806621490
88  160611535360618762
89  153340758003385986
90  145800774190430760
91  138082647938002508
92  130271158391553242
93  122443988821502259
94  114671214858346804
95  107014965207142134
96  99529316953401488
97  92260318022597233
98  85246208282329046
99  78517740682068333
100  72098652514008614
101  66006199334529111
102  60251775159824131
103  54841552248003292
104  49777135329252582
105  45056197268658240
106  40673066658891714
107  36619283524849712
108  32884076638726293
109  29454833177593810
110  26317485122896863
111  23456908635875939
112  20857234388365595
113  18502182572119847
114  16375303784595863
115  14460246361373049
116  12740927756506924
117  11201725269315914
118  9827577691852470
119  8604097298922082
120  7517623435041577
121  6555279475092260
122  5704999087362183
123  4955540166398617
124  4296494273383449
125  3718264495134961
126  3212064544051489
127  2769868097847448
128  2384402878185286
129  2049078806304698
130  1757974114299839
131  1505754391758305
132  1287659451250235
133  1099424037886546
134  937267436029853
135  797821186857866
136  678119270755147
137  575535421023447
138  487770924922894
139  412804404510562
140  348876645295098
141  294448665636652
142  248185443705358
143  208923745048864
144  175656730614255
145  147510746486271
146  123731973429538
147  103669456538203
148  86764842662111
149  72537378537783
150  60578177501888
151  50536214890777
152  42115446975801
153  35061321365011
154  29160887511157
155  24229958141802
156  20115834808496
157  16685484152606
158  13829697883806
159  11453236393604
160  9478404992247
161  7837593101077
162  6476213784270
163  5346802795303
164  4411310509036
165  3636591415967
166  2996161862009
167  2466840298337
168  2030202536115
169  1669880317268
170  1373147467849
171  1128523301863
172  927259997087
173  761413559223
174  625048494164
175  512734560849
176  420467914638
177  344556136065
178  282280015222
179  231136351367
180  189242273117
181  154873544243
182  126752021339
183  103683420604
184  84815203997
185  69330282593
186  56671988874
187  46281850393
188  37801598801
189  30845298453
190  25179932440
191  20541744061
192  16769933064
193  13682171259
194  11172093269
195  9114126181
196  7440097275
197  6065370784
198  4947123565
199  4028486998
200  3282838119
201  2670711130
202  2175609709
203  1769453489
204  1441628168
205  1172344299
206  954967135
207  776026493
208  631459648
209  512373550
210  416233569
211  337247139
212  273851883
213  221927233
214  180418481
215  146428507
216  119237728
217  96891799
218  78921329
219  64067771
220  52068026
221  42138314
222  34152371
223  27577320
224  22336328
225  18033977
226  14624710
227  11818153
228  9592127
229  7747533
230  6276629
231  5048967
232  4071153
233  3262152
234  2626975
235  2105501
236  1704582
237  1374301
238  1122858
239  911228
240  748223
241  605405
242  493552
243  394883
244  319773
245  253232
246  204620
247  161517
248  130825
249  103624
250  84595
251  67510
252  54946
253  43403
254  34836
255  26996
256  21567
257  16728
258  13534
259  10811
260  9074
261  7536
262  6342
263  5206
264  4290
265  3422
266  2750
267  2126
268  1663
269  1250
270  971
271  735
272  626
273  509
274  420
275  324
276  257
277  184
278  141
279  93
280  76
281  55
282  56
283  45
284  46
285  35
286  36
287  25
288  26
289  15
290  16
291  5
292  5
293  4
294  4
295  3
296  3
297  2
298  2
299  1
300  1


Ich muss schon sagen: Das war ein hartes Problem.

Beste Grüße
Mathematiker


Mathematiker - Mo 31.03.14 22:53

Hallo,
user profile iconjackle32 hat folgendes geschrieben Zum zitierten Posting springen:
Ich finde den Code echt schnell und habe bis jetzt noch nicht wirklich verstanden wie der funktioniert :eyecrazy: :bawling: .

Tut mir leid, ich hatte vergessen den Algorithmus noch zu erklären.
Allerdings werde ich Spares und Strikes und die Zusatzwürfe im 10.Frame mal nicht berücksichtigen, da diese für den Algorithmus unwichtig sind.

Ursprünglich rechnest Du je Frame 66 Möglichkeiten und damit 66^10 = 1,5 Trillionen Schritte. Und das dauert.
Mit den Frames 1,2,3,... werden es 66, 4356, 287496, ... Berechnungen.

Ich rechne am Anfang einen Frame (66 Berechnungen). Das Ergebnis speichere ich einer Tabelle. Diese enthält für die (normalen) Punktzahlen von 0 bis 270 jeweils, auf wie viele Möglichkeiten ich zu den jeweiligen Punkten gelangt bin und natürlich ob ein Spare oder Strike geworfen wurde.
Für diese 270 Punktmöglichkeiten rechne ich einen weiteren Frame, berücksichtige aber, dass ich jede nun erreichbare Punktmöglichkeit mit den im vorhergehenden Frame ermittelten Häufigkeiten multiplizieren muss.
Damit brauche ich für den 2.Frame insgesamt 66 + 270*66 = 17886 Rechnungen.

Dieses Verfahren wiederhole ich nun noch 8 mal. Im Ergebnis brauche ich also nur
66 + 9 * (270*66) = 160446 Berechnungen.
Das ist weniger als bei 3 Frames nach der ursprünglichen Methode. Und deshalb ist es so schnell.
Die Komplexität des Algorithmus sinkt damit von exponentiell auf linear (denke ich :nixweiss: ).
In 1 Sekunde Rechenzeit könnte ich wahrscheinlich so mehr als 1000 aufeinanderfolgende Frames durchrechnen. Natürlich geht das nicht, da ich dann die int64-Grenze überschreiten würde. Außerdem müsste die Tabelle größer werden, was wiederum Rechenzeit kostet.

user profile iconThorsten83 hatte ja schon auf den Begriff "dynamische Programmierung" hingewiesen.
Wenn meine Erklärung zu verwirrend ist, kannst Du ja unter http://de.wikipedia.org/wiki/Dynamische_Programmierung nachlesen. Dort ist es sicher besser erklärt.

Beste Grüße
Mathematiker


Horst_H - Di 01.04.14 07:35

Hallo,

Das ist das gleiche Prinzip wie bei der Bestimmung der Häufigkeit einer gewissen Augenzahl bei n -Würfen mit x - Würfeln mit z Seiten.( dort habe ich z = 6 vorgegeben, hier wäre es 0..30 ). Weshalb mein Codeschnipsel Augensumme hieß.
Alle Kombinationsmöglichkeiten der Würfel ermitteln [http://www.entwickler-ecke.de/viewtopic.php?t=112655]
Ein schlechter Titel.

Gruß Horst


Thorsten83 - Di 01.04.14 10:56

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Die Komplexität des Algorithmus sinkt damit von exponentiell auf linear (denke ich :nixweiss: ).


Genau genommen stimmt das nicht :)
Da die Anzahl der Würfe sowie die erzielbaren Punkte durch einen konstanten Wert beschränkt sind, hat man in beiden Fällen eine konstante Laufzeit.
Das ist ein schönes Beispiel dafür, dass die asymptotische Komplexität von Algorithmen zwar ein vielen Fällen hilfreich ist, aber nicht immer.

Grüße,
Thorsten


Xion - Di 01.04.14 14:06

Das stimmt nur, wenn man sich genau auf die Aufgabenstellung bezieht. Dort ist die Anzahl der Frames vorgegeben, und damit ist die Laufzeit konstant (übrigens auch im naiven Fall, alle Möglichkeiten durchzuprobieren).
Wenn man aber, wie Mathematiker sagte, bestimmen will, wielange die Berechnung in etwa bei 1000 Frames dauern würde, dann ist die Komplexität auf jeden Fall relevant. Natürlich könnte man wieder sagen, sie ist konstant, aber das hilft einem nicht weiter :nixweiss:

Sind n die Anzahl der Frames, dann ergibt sich die Laufzeit als:
O(66 + n*(30*n*66)) = O(n^2)
Da sowohl die Anzahl der Iterationen, als auch die Anzahl der Punkte von der Anzahl der Frames abhängig ist, ist dies ein Algorithmus mit quadratischer Laufzeit. Ganz klassisch für dynamische Programmierung, bei der oft eine zweidimensionale Tabelle (Frames x Punkte) gefüllt wird.

Bei 1000 Frames käme man also in eine Region von 2000 Millionen Möglichkeiten. Das sollte kein Problem darstellen.


Mathematiker - Di 01.04.14 14:45

Hallo,
user profile iconXion hat folgendes geschrieben Zum zitierten Posting springen:
Bei 1000 Frames käme man also in eine Region von 2000 Millionen Möglichkeiten. Das sollte kein Problem darstellen.

Ich habe aus Spaß einmal 100 bis 1000 Frames durchgerechnet.
int64 musste ich gegen extended tauschen und den Stack auf das 4fache erhöhen. Andernfalls wollte er die Felder nicht mehr nehmen.
Meine erste Vermutung (1s! :autsch: ) war zu optimistisch, aber es ist dennoch in vertretbarer Zeit machbar. Auf die Ausgabe der Einzelwerte habe ich aber verzichtet. :wink:


Quelltext
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:
100 Frames
Summe 3,90135663009767E182
Zeit 0,4 s

200 Frames
Summe 3,51244235889393E364
Zeit 1,6 s

300 Frames
Summe 3,16229775800925E546
Zeit 3,5 s

400 Frames
Summe 2,84705799797363E728
Zeit 6,2 s

500 Frames
Summe 2,56324352230777E910
Zeit 9,7 s

600 Frames
Summe 2,30772164084085E1092
Zeit 14,0 s

700 Frames
Summe 2,07767195167253E1274
Zeit 19,1 s

800 Frames
Summe 1,8705552101136E1456
Zeit 24,9 s

900 Frames
Summe 1,68408530098625E1638
Zeit 31,6 s

1000 Frames
Summe 1,51620400491987E1820
Zeit 39,0 s

Trägt man auf der Abszisse die Frames in 100 ab und auf der Ordinate die Laufzeit, so ergibt sich eine "schöne" quadratische Kurve.
codediagramm

Beste Grüße
Mathematiker


jackle32 - Di 01.04.14 20:29

Hallo nochmal,

ich komme mir ja schon langsam wie so ein Dauernörgler vor, aber eine kleine Anmerkung hab ich doch wieder. :oops:

Und zwar hierzu:

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
Im 10.Frame gibt es 55 Möglichkeiten Pins stehen zu lassen, ohne einen weiteren Wurf. 10 Möglichkeiten für einen Spare mit einem weiteren Wurf mit 11 möglichen Ausgängen. Der 1 Strike hat 2 Würfe zur Folge mit je 11 Ausgängen.
Damit gibt es im 10.Frame 55 + 10*11 + 1*11*11 = 286 Möglichkeiten und insgesamt für ein Bowling-Game


Ich kann deinen Argumenten nicht ganz folgen. Wo kommen die 55 her? Gleich noch vorne weg, meine Ursprüngliche Behauptung mit 241 war auch falsch, da hatte ich mich einfach verzählt.
Jetzt zu der neuen Berechnung:

Für die ersten beiden Würfe gibt es die üblichen 66 Möglichkeiten + 10 wegen der Sonderregelung, dass auch bei einem Strike im erste Wurf noch ein zweiter folgen darf, also 76 Möglichkeiten.
Hinzu kommen im Falle eines Strikes im ersten oder Spare im Zweiten ein dritter Wurf und hier wird es jetzt auch schwieriger. Da die Annahme bei Strike im ersten Wurf des 10. Frames mit zwei vollen 11 Möglichkeiten nicht richtig ist.
Hier nur beispielhaft ein Fall wie ich meine:
1.Wurf: Strike
2. Wurf: 5
Somit bleiben für den dritten Wurf nur die Möglichkeiten: 0,1,2,3,4 oder Spare. Also 6 Möglichkeiten.

Es gibt nach den ersten beiden Würfen 12 Varianten wo im dritten Wurf 11 Möglichkeiten vorhanden sind. Das sind 132 Möglichkeiten.
So und dann gibt es wie oben beschrieben noch die Fälle in denen im ersten Wurf aber nicht im zweiten ein Strike geworfen wurde. Das sind dann nochmal 54 Möglichkeiten. (Markierung in Tabelle)


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
1. Wurf | 2. Wurf | 3. Wurf | Möglichekeiten
X         0          0-X         11

X         1          0-8, Y      10
X         2          0-7, Y       9
X         3          0-6, Y       8
X         4          0-5, Y       7
X         5          0-4, Y       6
X         6          0-3, Y       5
X         7          0-2, Y       4
X         8          0-1, Y       3
X         9          0, Y         2

X         X          0-X         11


Somit komme ich auf
76 + 132 + 54 = 262 Möglichkeiten

Was auch noch nicht ganz passen kann, ist das es mehr als eine Möglichkeit gibt 298 Punkte zu erreichen. Für die Punkte von 291 bis 300 gibt es nur jeweils eine Möglichkeit diese zu erreichen.
Und zwar sind diese Punkte nur möglich bei 11 Strikes und 1 bis 10 Punkte im letzten Wurf. Sobald vorher eine Strike fehlt, fehlen in der Summe sofort mindestens 10 Punkte und ich kann nur noch höchstens 290 Punkte erreichen. (Klar ist natürlich wenn der Strike in einem der ersten Frames fehlt, fehlen sofort weit mehr als 10 Punkte).

So jetzt genug geredet, ich bin mir sicher, dass wird auch wieder kein Problem für euch darstellen.

Gruß,
Jack


Mathematiker - Di 01.04.14 21:27

Hallo,
also irgendwie habe ich Probleme diesen 10.Frame zu verstehen. Vielleicht stimmt es jetzt.

Also: Für den 1.Wurf im 10.Frame gibt es 11 Möglichkeiten. Einer davon ist der Strike. Für die Restlichen ergibt sich kein Spare, wenn

Quelltext
1:
2:
3:
4:
5:
6:
1.Wurf ... 2.Wurf
0      ... 0 bis 9
1      ... 0 bis 8
2      ... 0 bis 7
...
9      ... 0

Das sind insgesamt 55 Möglichkeiten, die nicht zum Spare führen. Die verbleibenden 10 führen zum Spare.
Nach dem Spare folgt noch 1 Wurf mit 11 Möglichkeiten, d.h. insgesamt für den Spare = 10*11 Möglichkeiten.

Nach dem Strike folgt ein 1.Wurf mit 11 Möglichkeiten. 10 davon räumen nicht ab und ergeben für den 2. weiteren Wurf

Quelltext
1:
2:
3:
4:
5:
6:
1.Wurf ... 2.Wurf
0      ... 0 bis 10
1      ... 0 bis 9
2      ... 0 bis 8
...
9      ... 0 bis 1

mit insgesamt 65 Möglichkeiten. Sollte der 1.Zusatzwurf ein Strike sein, wird neu aufgesetzt, mit 11 Wurfmöglichkeiten im 2.Zusatzwurf. Für den Strike werden das insgesamt 65 + 1 * 11 Möglichkeiten.
Fügen wir alles zusammen, gibt es im 10.Frame
55 + 10·11 + 65 + 11 = 241 Möglichkeiten. Und damit war Deine erste Bemerkung richtig. Ich hatte mich vertan.

Für das ganze Bowling-Game also

Quelltext
1:
11^9·6^9·(55 + 10·11 + 65 + 11) = 5726805883325784576                    

Jetzt müsste es stimmen.

Und damit wird für den Quelltext:

Delphi-Quelltext
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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
procedure TForm1.Button15Click(Sender: TObject);
var feld,feld2:array[0..300,0..3of int64;
    pu,nr,strikespare:integer;
    abbruch:integer;
    frames:integer;
    i,j,m:integer;
    faktor,summe:int64;
    summand:int64;
    t1x,t2x,frequenz : TLargeInteger;
    laeufe:integer;
    moeglich:integer;
procedure wurf(nr:integer;moeglich:integer;pu:integer;strikespare:integer);
var i,zusatz,doppelt:integer;
begin
    if nr>abbruch then
    begin
      feld[pu+summand,strikespare]:=faktor+feld[pu+summand,strikespare];
      exit
    end;

    for i:=0 to moeglich do
    begin
      if strikespare>0
      then
      begin
        zusatz:=i;
        doppelt:=0;
        if strikespare>2 then begin zusatz:=2*i; doppelt:=1 end;
        if odd(nr) then
        begin
          if i=moeglich then wurf(nr+2,10,pu+i+zusatz,strikespare+1-doppelt)
                        else wurf(nr+1,10-i,pu+i+zusatz,strikespare-1-doppelt)
        end
        else
        begin
          if i=moeglich then wurf(nr+1,10,pu+i+zusatz,strikespare-doppelt)
                        else wurf(nr+1,10,pu+i+zusatz,strikespare-1-doppelt)
        end;
      end
      else
      begin
        if odd(nr) then
        begin
          if i=moeglich then wurf(nr+2,10,pu+i,strikespare+2)
                        else wurf(nr+1,10-i,pu+i,strikespare)
        end
        else
        begin
          if i=moeglich then wurf(nr+1,10,pu+i,strikespare+1)
                        else wurf(nr+1,10,pu+i,strikespare)
        end;
      end;
    end
end;
begin
    listbox1.clear;

    frames:=10;
    nr:=1;
    pu:=0;
    strikespare:=0;
    fillchar(feld,sizeof(feld),0);
    fillchar(feld2,sizeof(feld2),0);
    abbruch:=2;
    QueryPerformanceFrequency (frequenz);      // Frequenz des Zählers
    QueryPerformanceCounter (t1x);       // Zählerstand 1

    faktor:=1;
    summand:=0;
    wurf(nr,10,pu,strikespare);

    for laeufe:=1 to frames-1 do
    begin
      feld2:=feld;
      fillchar(feld,sizeof(feld),0);
      for j:=0 to 30*frames do
        for m:=0 to 3 do
        begin
          if feld2[j,m]>0 then
          begin
            faktor:=feld2[j,m];
            summand:=j;
            nr:=1;
            pu:=0;
            strikespare:=m;
            wurf(nr,10,pu,strikespare);
          end;
        end;
    end;

    feld2:=feld;
    for j:=0 to 270 do begin
        if (feld2[j,3]>0then //strike im 9. und 10.
        begin
          dec(feld[j,0],feld2[j,3]);
          for i:=0 to 10 do
          begin
            if i=10 then moeglich:=10
                    else moeglich:=10-i;
            for m:=0 to moeglich do begin
              inc(feld[j+m+2*i,0],feld2[j,3])
            end;
          end;
        end;
        if (feld2[j,2]>0then //strike im 10. nicht im 9.
        begin
          dec(feld[j,0],feld2[j,2]);
          for i:=0 to 10 do
          begin
            if i=10 then moeglich:=10
                    else moeglich:=10-i;
            for m:=0 to moeglich do begin
              inc(feld[j+m+i,0],feld2[j,2])
            end;
          end;
        end;
        if feld2[j,1]>0 then //spare im 10.
        begin
          dec(feld[j,0],feld2[j,1]);
          for i:=0 to 10 do inc(feld[j+i,0],feld2[j,1]);
        end;
    end;
    QueryPerformanceCounter (t2x);       // Zählerstand 2

    summe:=0;
    for j:=0 to 30*frames do
    begin
      listbox1.items.add(inttostr(j)+#9+inttostr(feld[j,0]+feld[j,1]+feld[j,2]+feld[j,3]));
      summe:=summe+feld[j,0]+feld[j,1]+feld[j,2]+feld[j,3];
    end;
    listbox1.items.insert(0,inttostr(frames)+' Frames');
    listbox1.items.insert(0,'Summe '+inttostr(summe));
    listbox1.items.insert(0,'Zeit '+FormatFloat('0.0 ms',1000*(t2x-t1x)/frequenz));
    application.processmessages;
    listbox1.items.savetofile('Lrekursiv.txt');
end;


als Endergebnis folgt damit

Quelltext
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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
Zeit 3,1 ms
Summe 5726805883325784576
10 Frames
0  1
1  20
2  210
3  1540
4  8855
5  42504
6  177100
7  657800
8  2220075
9  6906900
10  20030010
11  54627084
12  141116637
13  347336412
14  818558424
15  1854631380
16  4053948342
17  8574134256
18  17590903116
19  35084425512
20  68153183370
21  129156542039
22  239128282128
23  433093980298
24  768175029950
25  1335679056261
26  2278764308864
27  3817721269708
28  6285424931278
29  10176048813473
30  16210652213304
31  25423690787719
32  39274771758064
33  59789973730461
34  89736657900900
35  132834787033075
36  194006223597572
37  279661205716974
38  398018151390200
39  559449136091831
40  776838931567572
41  1065940588576732
42  1445705502357343
43  1938561121705315
44  2570605432880903
45  3371684590465908
46  4375319099346208
47  5618445228564793
48  7140942201229333
49  8984922304030443
50  11193770355829009
51  13810930667765157
52  16878453276117746
53  20435326129713654
54  24515635362932954
55  29146610869639549
56  34346628376654913
57  40123251227815383
58  46471404549689351
59  53371780703441318
60  60789577452586487
61  68673668434334934
62  76956298564663402
63  85553384395717227
64  94365480254213528
65  103279445170253902
66  112170812747354087
67  120906827121834566
68  129350064451661348
69  137362512979745598
70  144809940796620325
71  151566341291631624
72  157518221668013078
73  162568486673578693
74  166639683923175378
75  169676402232105648
76  171646676234883305
77  172542309343731946
78  172378125687965848
79  171190226627438257
80  169033430825208027
81  165978103316094584
82  162106654714921075
83  157509948809043576
84  152283892386077931
85  146526364181517039
86  140334651650668803
87  133803399444707801
88  127023103852577896
89  120079021507938035
90  113050455155943519
91  106010240661754449
92  99024411737621323
93  92151904402003308
94  85444345654857875
95  78945863453573001
96  72693023944120045
97  66714881583314335
98  61033240145235763
99  55663091133973346
100  50613244155051856
101  45887089510794122
102  41483436078768079
103  37397371704961189
104  33621048067136846
105  30144388614623696
106  26955619314626157
107  24041709119775647
108  21388640692533960
109  18981680119465910
110  16805547548715206
111  14844654231857239
112  13083276623221517
113  11505812292077067
114  10096971927616045
115  8842020009154293
116  7726929590817265
117  6738528470417086
118  5864552560171552
119  5093653838062639
120  4415377510495980
121  3820097597373727
122  3298981687014508
123  2843905747206868
124  2447444695948898
125  2102793053565659
126  1803790254604935
127  1544848145184291
128  1320992367181792
129  1127775864826813
130  961294388171457
131  818085023387881
132  695128788327698
133  589753122859383
134  499630252931260
135  422696870992462
136  357151976811922
137  301400973036441
138  254052574077937
139  213889601295347
140  179862464456172
141  151065169242834
142  126722015973414
143  106169469752641
144  88840622360686
145  74252067274687
146  61990415093876
147  51701385089887
148  43082666091665
149  35870481552300
150  29843343433392
151  24808172866872
152  20607116162379
153  17101443169235
154  14181008701762
155  11747089496422
156  9723545122578
157  8040378083433
158  6644452641044
159  5486702080236
160  4529003381568
161  3736165201688
162  3081105018158
163  2539255963377
164  2091793858275
165  1721930513702
166  1416734360140
167  1164733232308
168  957190045595
169  785911852914
170  645295369580
171  529489941608
172  434606120455
173  356481490646
174  292487050484
175  239755303889
176  196550315542
177  160954253448
178  131791387388
179  107847709116
180  88241591630
181  72162948863
182  59038079745
183  48284335855
184  39509743432
185  32308399043
186  26423428886
187  21582203262
188  17624621529
189  14368737009
190  11720626558
191  9552812749
192  7790240907
193  6351933169
194  5185250585
195  4232118751
196  3457204258
197  2821392492
198  2302090127
199  1874802017
200  1526313637
201  1239515641
202  1007719386
203  818568928
204  666193896
205  542061609
206  442072320
207  360234562
208  293886739
209  239045260
210  194337731
211  157306293
212  127325163
213  102799565
214  83194097
215  67300605
216  54691522
217  44477808
218  36317458
219  29606794
220  24117404
221  19554213
222  15820964
223  12736481
224  10258846
225  8244157
226  6659561
227  5381526
228  4385243
229  3576841
230  2930385
231  2376760
232  1924226
233  1541327
234  1231527
235  975760
236  777090
237  617547
238  498228
239  404981
240  335065
241  275998
242  226966
243  183727
244  148442
245  117291
246  93525
247  73010
248  57960
249  45826
250  37965
251  31193
252  26131
253  21406
254  17422
255  13613
256  10696
257  7975
258  6005
259  4374
260  3534
261  3016
262  2635
263  2264
264  1933
265  1603
266  1323
267  1045
268  810
269  585
270  406
271  277
272  258
273  227
274  206
275  173
276  150
277  115
278  90
279  53
280  26
281  15
282  15
283  14
284  14
285  13
286  13
287  12
288  12
289  11
290  11
291  1
292  1
293  1
294  1
295  1
296  1
297  1
298  1
299  1
300  1


Ich kann nur hoffen, dass es jetzt stimmt.
Auf jeden Fall werde ich keine Bowling-Bahn mehr betreten. Das ist mir alles viel zu kompliziert. :wink:

Beste Grüße
Mathematiker


jackle32 - Di 01.04.14 21:53

Hallo,

also ich hab jetzt auch nochmal nachgezählt und hab gemerkt, wenn ich keine Möglichkeiten doppelt zähle stimmen meine Ursprünglichen 241. :gruebel:

Also bleibt es bei den angesprochenen 5726805883325784576 Möglichkeiten.

Jetzt sehen alle Werte auf jeden Fall plausibel aus. :flehan:

Bin doch immer beeindruckt wie schnell und ergiebig diese Forum ist. :zustimm:

Danke an alle die Mitdiskutiert haben.

@Mathematiker:
Sorry wenn ich dir jetzt das bowlen vermiest habe, aber immerhin weißt du jetzt wann du statistisch betrachtet gut spielst :wink:

Gruß,
Jack