Klasseneinteilung beim Kniffel

Neue Frage »

Dopap Auf diesen Beitrag antworten »
Klasseneinteilung beim Kniffel
ich schrieb im Thread Kombinatorik - Kniffel

dass es 3600 Blöcke der Form aabcd (= genau ein Paar) beim Kniffel gebe von insgesamt 7776 Blöcken.
Das möchte ich simulieren und statistisch überprüfen. Dazu werden viele Arrays erstellt, die das Ergebnis eines Wurfes enthält z.B



Es steht mir zusätzlich z.B. der Befehl der im obigen Falle eine Null zurückgibt, im Wahr-Fall eine 1.

Wie wäre denn programmtechnisch eine geschickte Abfrage zu formulieren ?

code:
1:
2:
3:
4:
5:
6:
7:
IF POS(2)=1 
THEN ...
ELSE ....
    IF ....
    THEN .... 
    ELSE .... END END ...................
verwirrt
Dopap Auf diesen Beitrag antworten »

mit dem kleinen Hilfsprogramm

das zählt wie oft x im Array W auftritt geht es wohl am einfachsten.

IF COUNT(W,2)=1 AND COUNT(W,3)=0 THEN ... END

dürfte genau 1 Paar gefunden werden.

edit: filtert man von oben her 5Pasch - 4Pasch - Full house - 3Pasch - 2Paare ,
dann genügt natürlich COUNT(W,2)=1.
Die Straße ist dann auch kein Problem mehr:
IF COUNT(W,0)=0 THEN Straße END und die Klasseneinteilung ist fertig.
SHigh Auf diesen Beitrag antworten »

Zitat:
Die Straße ist dann auch kein Problem mehr: IF COUNT(W,0)=0 THEN Straße END


Bei einer Straße bekommt man doch zwangsläufig eine Null, weil man nur fünf Würfel hat, oder?

Dann fällt mir nur

IF COUNT(W,2)=0 AND COUNT(W,3)=0 AND COUNT(W,4)=0 AND COUNT(W,5)=0 THEN ...

ein, oder geht das nicht viel schöner verwirrt ?


Hat sich das Ergebnis mit dem "genau 1 Paar" denn bestätigt?
Dopap Auf diesen Beitrag antworten »

Zitat:
Original von SHigh

Bei einer Straße bekommt man doch zwangsläufig eine Null, weil man nur fünf Würfel hat, oder?


richtig, bin selbst bei 5 Würfel und 6 Möglichkeiten durcheinander.
Die 0 aber muss vorne oder hinten sitzen. Als Einzelabfrage mMn:

IF (W(1)=0 OR W(6)=0) AND COUNT(W,0) = 1 THEN .... END

Zitat:

Hat sich das Ergebnis mit dem "genau 1 Paar" denn bestätigt?


Ja und nein !! traurig

Eine Simulation mit n=100.000 brachte p(1 Paar )= 46.9% gegenüber 46.3% nach Theorie. Sieht erst mal gut aus.
Leider sind das ca. 3 SigmaEinheiten Abstand.

Woran könnte das liegen verwirrt
SHigh Auf diesen Beitrag antworten »

Zitat:
richtig, bin selbst bei 5 Würfel und 6 Möglichkeiten durcheinander. Die 0 aber muss vorne oder hinten sitzen.


Richtig, das ist mir ja schon fast peinlich...

Zur Überprüfung würde ich zum Binomialtest raten. Teste zweiseitig



mit den kritischen Werten



und

.

Als Teststatistik zählst du einfach die Erfolge, also bei dir sollte sein (oder eben den ungerundeten Wert).
Huggy Auf diesen Beitrag antworten »

@SHigh
Bei 100 000 Simulationen und kann man zur Abschätzung der Genauigkeit schon die Näherung der Binomialverteilung durch die Normalverteilung benutzen, wie es Dopap gemacht hat.

@Dopap
Um dein Programm zu überprüfen, könntest mal das Würfeln durch das systematische Erzeugen aller Kombinationen (5 Laufanweisungen für die 5 Würfel) ersetzen. Es muss ja dann 3600 herauskommen. Das läuft auch viel schneller als die Simulation.

Ich habe es mal auf die Schnelle in Mathematica programmiert und da passt beides, systematisches Erzeugen und Simulation.

Generell ist mit aber unklar, weshalb du ein offensichtlich richtiges Resultat noch mit einem Programm prüfen möchtest.
 
 
Dopap Auf diesen Beitrag antworten »

Irgendwo musste ein kleiner "unbedeutender" Fehler stecken.

Typisch: der COUNT(W,x) lief nur bis 5 und nicht bis 6, was natürlich doppelte Paare mit 2 Sechsen und Full House mit 3 Sechsen mitzählte .

Man sollte eben auch die vermeintlich kleinen Programme immer zuerst testen.
Leopold Auf diesen Beitrag antworten »

Ich habe ein Programm mit Lazarus (Delphi/Object-Pascal) geschrieben. Es enthält ein Memo-Objekt AusgabeMemo und einen Button AusfuehrenButton, dessen OnClick-Prozedur ausfuehren (ganz unten im Code) heißt.

code:
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:
type
  TMuster       = (ABCDE,AAABC,AAAAA,AAAAB,AABCD,AABBC,AAABB);
  TMusterAnzahl = array[ABCDE..AAABB] of Integer;
  TAusgang      = array[1..5] of Byte;
  TAnzahl       = array[1..6] of Byte;

var
  musterAnzahl: TMusterAnzahl = (0,0,0,0,0,0,0);

function musterToStr(muster: TMuster): String;
var
  y: String;
begin
  case muster of
    ABCDE: y:='ABCDE';
    AAABC: y:='AAABC';
    AAAAA: y:='AAAAA';
    AAAAB: y:='AAAAB';
    AABCD: y:='AABCD';
    AABBC: y:='AABBC';
    AAABB: y:='AAABB';
  end;
  musterToStr:=y;
end;

procedure sortiere(var anzahl: TAnzahl);
var
  i,j,max,iMax: Byte;
begin
  for i:=1 to 5 do
  begin
    max:=anzahl[i]; iMax:=i;
    for j:=i+1 to 6 do if anzahl[j]>max
    then begin
      max:=anzahl[j];
      iMax:=j;
    end;
    for j:=iMax downto i+1 do anzahl[j]:=anzahl[j-1];
    anzahl[i]:=max;
  end;
end;

function muster(ausgang: TAusgang): TMuster;
var
  anzahl: TAnzahl;
  i:      Byte;
  y:      TMuster;
begin
  for i:=1 to 6 do anzahl[i]:=0;
  for i:=1 to 5 do inc(anzahl[ausgang[i]]);
  sortiere(anzahl);
  if anzahl[1]=5 then y:=AAAAA
  else if anzahl[1]=4 then y:=AAAAB
  else if anzahl[1]=3 then if anzahl[2]=2 then y:=AAABB else y:=AAABC
  else if anzahl[1]=2 then if anzahl[2]=2 then y:=AABBC else y:=AABCD
  else y:=ABCDE;
  muster:=y;
end;

procedure MusterAnzahlenBestimmen;
var
  i1,i2,i3,i4,i5: Byte;
  ausgang:        TAusgang;
begin
  for i1:=1 to 6 do
  for i2:=1 to 6 do
  for i3:=1 to 6 do
  for i4:=1 to 6 do
  for i5:=1 to 6 do
  begin
    ausgang[1]:=i1; ausgang[2]:=i2; ausgang[3]:=i3;
    ausgang[4]:=i4; ausgang[5]:=i5;
    inc(musterAnzahl[muster(ausgang)]);
  end;
end;

procedure TTestForm.ausfuehren(Sender: TObject);
const
  TAB = #9;
var
  muster: TMuster;
begin
  musterAnzahlenBestimmen;
  ausgabeMemo.Clear;
  for muster:=ABCDE to AAABB do
    ausgabeMemo.Lines.Append(musterToStr(muster)+':'+TAB
    +intToStr(musterAnzahl[muster]));
end;

Das Programm liefert die folgende Ausgabe.

[attach]44747[/attach]

siehe auch hier
Dopap Auf diesen Beitrag antworten »

einfach überzeugend !

Das letzte in programmieren war bei mir Turbo Pascal ca. 1992.
Verwendet man statt Würfel Zufallsziffern, so kann man diese mit der Klasseneinteilung des Pokertestes testen.
Zumindest eine Klasse hat mein Zufallsgenerator im TR also bestanden. smile
HAL 9000 Auf diesen Beitrag antworten »

Auch der allgemeine Fall ist kombinatorisch nicht so kompliziert, das schlimmste daran ist noch die leider notwendige Einführung aller benötigten Symbole:

Wir betrachten Auswahlen von Elementen aus mit Wiederholung und Reihenfolge, d.h. insgesamt Variationen.

Unter diesen -Tupeln suchen wir nun diejenigen mit genau -mal jeweils gleichen Komponenten (), wobei gelten soll. Diese Typisierung soll vollständig sein, d.h. (Anzahl verschiedener Elemente in der Auswahl) und (Anzahl der Elemente in den Klassen), d.h. evtl. einzeln vorkommende Elemente müssen mit und auch gar nicht vorkommende Elemente mit erfasst werden! Die Anzahl solcher Tupel ist dann

.

Bsp. oben

.


Und was (zumindest für größere ) auch nicht trivial ist: Die Erfassung aller möglichen Klassen, also über die Parameter , die für gegebenes n,m jeweils möglich sind. Augenzwinkern
Leopold Auf diesen Beitrag antworten »

Das steht ja bereits im von mir angegebenen Link.

@ Dopap

Es geht auch mit einem "antiken" Turbo-Pascal-Programm. Den Programmcode kann man fast vollständig übernehmen. Lediglich in

var
musterAnzahl: TMusterAnzahl = (0,0,0,0,0,0,0);


ist var durch const zu ersetzen. Und die Ausgabe am Bildschirm erfolgt über das Hauptprogramm. Die Bilder zeigen die Ausführung in einer DOS-Box.

[attach]44755[/attach] [attach]44756[/attach]
[attach]44757[/attach]
HAL 9000 Auf diesen Beitrag antworten »

Zitat:
Original von Leopold
Das steht ja bereits im von mir angegebenen Link.

Der Spezialfall m=10,n=5 steht da - oder du meinst einen anderen Link.

code:
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:
#include <iostream>
#include <gmpxx.h>

class CVariationPartition
{
public:
    CVariationPartition () { nF = 0;  zF = NULL; }
    ~CVariationPartition () { delete[] zF; }
    void PrintPartitions (int _m, int _n);
private:
    int   m;
    int   n;
    int   nF;
    int  *p;
    mpz_class sum;
    mpz_class *zF;
    void RecPartition (int start, int min, int rest);
};

using namespace std;

void CVariationPartition::RecPartition (int start, int min, int rest)
{
    if (start >= m-1)
    {
        if (rest >= min)
        {
            // Partition Ok, kann ausgewertet werden
            p[start] = rest;
            mpz_class mp = zF[m];
            mpz_class count = zF[n];
            int r0 = 0, s = 0;
            for (int i = 0; i < m; i++)
            {
                int r = p[i];
                count /= zF[r];
                if (r == r0) s++; else
                {
                    mp /= zF[s];
                    r0 = r;  s = 1;
                }
            }
            count *= (mp / zF[s]);
            sum += count;
            // Jetzt ausgeben
            int i = m-1;
            char c = 'A';
            while ((i >= 0) && (p[i] > 0))
            {
                for (int j = 0; j < p[i]; j++) cout << c;
                c++;  i--;
            }
            cout << "\t" << count << endl;
        }
        return;
    }
    // Partitionswert an Stelle "start" festlegen und rekursiv abtauchen
    rest -= min;
    while (rest >= min)
    {
        p[start] = min;
        RecPartition(start+1, min, rest);
        min++;  rest--;
    }
}

void CVariationPartition::PrintPartitions (int _m, int _n)
{
    m = _m;  n = _n;
    int size = (m > n ? m : n) + 1;
    if (size > nF)
    {
        delete [] zF;
        // Hilfsarray Fakultäten
        nF = size;
        zF = new mpz_class[nF];
        zF[0] = 1;
        for (int i = 1; i < nF; i++) zF[i] = i * zF[i-1];
    }
    // Zahlpartition von n in maximal m Summanden, aufsteigend geordnet
    sum = 0;
    p = new int[m];
    RecPartition(0, 0, n);
    cout << "sum\t" << sum << endl;
    delete[] p;
}

int main (int argc, char *argv[])
{
    CVariationPartition p;
    if (argc < 3)
    {
        cerr << "Usage: " << argv[0] << " <m> <n>" << endl;
        return 1;
    }
    p.PrintPartitions(atoi(argv[1]), atoi(argv[2]));
    return 0;
}
Sollte funktionieren, solange die Klassenzahl nicht ins Unermessliche (>10^9) steigt. Datentyp "mpz_class" aus der GMP gewährleistet die Speicherung auch sehr großer ganzer Zahlen, also CAS-mäßig.
Dopap Auf diesen Beitrag antworten »

Es wurde ja über das Ende des matheboards im Off-Topic schon diskutiert.

Aber hier bekommt der TS Antworten auf Fragen die er so gar nicht gestellt hat. ( Wenn er überhaupt nochmals vorbeischaut ! ), wo gibt's so was schon ?

Wenn ich es richtig verstehe, könnte somit alle Fragen zum Klingonen-Kniffel ( 8 Pentagondodekaeder werden geworfen ) beantwortet werden. Augenzwinkern
Neue Frage »
Antworten »



Verwandte Themen

Die Beliebtesten »
Die Größten »
Die Neuesten »