AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Spezielles Random

Ein Thema von Nils_13 · begonnen am 6. Jan 2011
Antwort Antwort
Nils_13

Registriert seit: 15. Nov 2004
2.647 Beiträge
 
#1

Spezielles Random

  Alt 6. Jan 2011, 17:42
Hi,

ich habe eine Funktion geschrieben, welche eine Liste von Zufallszahlen erstellt. Jede Zahl gehört einer Zahlenkategorie an. Pro Zufallsdurchlauf darf jeweils nur eine Zahl aus jeder Kategorie in der Liste am Ende auftauchen. Das heißt: 1=Kategorie 1; 2,3=Kategorie 2; 4,5=Kategorie 3. Nun kriege ich eine 2 als Zufallszahl. Also schreibe ich sie in die Liste und merke mir, dass sowohl 2 als auch 3 (da gleiche Kategorie) verworfen werden müssen, falls sie nochmal vorkommen sollten. Das geht solange weiter, bis keine Zahl mehr übrig bleibt. Man hat am Ende also eine Teilmenge aller Zufallszahlen, jede Zahlenkategorie nur einmal. Angenommen man hat 5 Kategorien, dann hätte man auch nur 5 Zufallszahlen obwohl es sagen wir mal 14 mögliche Zufallszahlen gibt. Das zu programmieren klingt ja einfach. Eine Prozedur erzeugt die besagte Liste und eine Funktion holt von Anfang bis Ende alle Zufallszahlen nach der Reihe raus und wenn die Funktion am Ende der Liste ist, lässt es über die Prozedur eine neue erstellen. So könnte man gleichmäßig nach Kategorien verteilte Zufallszahlen erhalten. Das geht sogar gut, aber irgendwann verabscheidet sich mein Programm mit dem CPU-Fenster vom Debugger. Die Prozedur und Funktion sind Teilbestandteil einer Prozedur, daher habe ich das so zerstückelt. Es hat aber seinen strukturellen Sinn. Die Zahlen 12,13,14 sollen ausgeschlossen werden, also nicht wundern, dass ich das tue.
Delphi-Quellcode:
procedure ...;
  // Zufallsarray
  var ArrRnd : TDynIntArr;
      RndAkt : Integer;
      ArrRndU : Array of Integer;
  procedure FillRndArr;
    // Zahlen in Zufallsarray einfügen
    procedure AddArr(Zahlen : Array of Integer);
    var i : Integer;
    begin
      for i := 0 to High(Zahlen) do
      begin
        SetLength(ArrRndU, High(ArrRndU)+2);
        ArrRnd[High(ArrRndU)] := Zahlen[i];
      end;
    end;
  var i, j, Zahl : Integer;
      Flag : Boolean;
  begin
    // Alles zurücksetzen
    RndAkt := 0;
    SetLength(ArrRndU, 0);
    SetLength(ArrRnd, 0);
    i := 0;
    while i < 4 do // 5 Zahlenkategorien gibt es
    begin
      // Zahl ermitteln und prüfen ob zulässig
      Zahl := Random(12);
      Flag := True;
      for j := 0 to High(ArrRndU) do
        if ArrRndU[j] = Zahl then
        begin
          Flag := False;
          Break;
        end;
      // Zahl ist zulässig
      if Flag then
      begin
        SetLength(ArrRnd, High(ArrRnd)+2);
        ArrRnd[High(ArrRnd)] := Zahl; // geht performanter, gerade weil ich ja im Voraus weiß, wie lang mein Array ist - nutzt aber nichts, ich will alles so einfach wie möglich halten erstmal, damit der Fehler beseitigt wird.
        // Kategorisierung
        case Zahl of
          0, 1 : AddArr([0, 1]);
          2, 3, 4, 5 : AddArr([2, 3, 4, 5]);
          6, 7, 8, 9 : AddArr([6, 7, 8, 9]);
          10 : AddArr([10]);
          11 : AddArr([11]);
        end;
        Inc(i);
      end;
    end;
  end;

  // Zufallszahl ermitteln. Jede Zahlenkategorie darf pro Zufallsdurchlauf nur einmal vorkommen.
  function RandomExclusive : Integer;
  begin
    Result := ArrRnd[RndAkt];
    Inc(RndAkt);
    if RndAkt = 4 then
      FillRndArr;
  end;
var i : Integer;
begin
  FillRndArr;
  RndAkt := 0;
  for i := 0 to 49 do
    RandomExclusive;
end;
Ich hoffe, es ist alles verständlich. Ich weiß nicht, was ich noch genauer erklären könnte, habe aber das dumme Gefühl, dass da keiner durchsteigt. Falls es jemand überhaupt nicht versteht:
1,2,3,4,5 ist der Zahlentopf (einfaches Beispiel).
1 ist eine Kategorie, 2 und 3 sind eine Kategorie, 4 und 5 sind ebenfalls eine Kategorie (per Definition!).
Es ist ein Array voller Zahlen gesucht, welches insgesamt von jeder Kategorie nur eine Zahl enthält. Beim jetzigen Beispiel also: 1, 2 oder 3, 4 oder 5. Beispielarray: 1, 3, 4 Es geht mir halt darum, dass die entsprechenden Zahlenkategorien relativ gleichmäßig verteilt werden. Vielleicht fällt jemanden ja auch eine andere einfacherere Variante ein. Das Problem sind halt die Kategorien. Sonst musste ich immer nur dafür sorgen, dass jeweils nur eine Zufallszall pro Durchlauf vorkam, aber es gab da keine Kategorien - das war nichts weiter als eine kleine Schleife die das erledigt hat, hier sieht es komplizierter aus leider.

Nochmal zu meinem Code: Angenomen im case läuft das Programm den Weg über 2,3,4,5. Dann beendet die Prozedur erfolgreich und sie wird erneut aufgerufen (50 mal - siehe Schleife unten). Es ist egal welchen Weg das Programm im case dann geht, außer wenn es WIEDER 2,3,4,5 ist - dann kommt die ungültige Zeigeroperation welche sogar teilweise den Debugger zum Absturz brachte. Das finde ich schon sehr merkwürdig. EDIT: Nochmal weiter rumgetestet. Der Fehler tritt auch auf, wenn case-Option 1 und 3 auftreten, scheint also nichts mit mehrfachem Aufruf zu tun zu haben.

Weiterer Nachtrag: Habe eine einfacherere Lösung gefunden und PROBIERT. Ganz einfach:
Delphi-Quellcode:
var ArrRndKat : Array[0..4] of Boolean;
  function RandomExclusive : Integer;
  var Flag, SFlag : Boolean;
      Zahl, i : Integer;
  begin
    Zahl := 0;
    Flag := True;
    while Flag do
    begin
      // Prüfen ob ArrRndKat wieder komplett auf False gesetzt werden müssen, also ob alle Zahlenkategorien verbraucht sind.
      SFlag := True;
      for i := 0 to 4 do
        if not ArrRndKat[i] then
        begin
          SFlag := False;
          Break;
        end;
      if SFlag then
        for i := 0 to 4 do
          ArrRndKat[i] := False;
      // Zahl bestimmen und falls die Zahl okay ist, direkt zurückgeben und Kategorie sperren.
      Zahl := Random(12);
      case Zahl of
        0, 1 : if not ArrRndKat[0] then begin Flag := False; ArrRndKat[0] := True; end;
        2, 3, 4, 5 : if not ArrRndKat[1] then begin Flag := False; ArrRndKat[1] := True; end;
        6, 7, 8, 9 : if not ArrRndKat[2] then begin Flag := False; ArrRndKat[2] := True; end;
        10 : if not ArrRndKat[3] then begin Flag := False; ArrRndKat[3] := True; end;
        11 : if not ArrRndKat[4] then begin Flag := False; ArrRndKat[4] := True; end;
      end;
    end;
    Result := Zahl;
  end;
Dann setzt man ArrRndKat noch voll auf False und das MÜSSTE laufen. Beim xten Durchlauf kracht es plötzlich (Ungültige Zeigeroperation) - nach erfolgreicher Ausführung - beim end; der Aufrufprozedur. Da platzte mir der Kragen und ich nahm den Code in ein mageres Testprojekt auf und hatte...Trommelwirbel...den gleichen Fehler. Noch wütender öffnete ich Lazarus und...Trommelwirbel...KEIN Fehler. Das ist dann das Ende von Delphi, der Compiler von Delphi7 macht generell Fehler die nicht mehr tragbar sind langsam. Dann kompilier ich lieber direkt mit dem FPC, die VCL von Delphi benutze ich eh schon lange nicht mehr. Schade, abgesehen vom fehlerhaften Compiler war D7 deutlich besser als Lazarus. Aber Compiler geht vor. Natürlich kann es sein, dass ich einen dummen Fehler gemacht habe, den bloß keiner sieht. Eventuell hängt es auch mit einer unvorstellbaren(!) 32- auf 64-bit Inkompatibilität zusammen (kann ich mir aber echt nicht vorstellen), Fakt ist, dass der Compiler auch einige andere Fehler hat und das jetzt leider sein Ende bedeutet, zumindest für große Projekte.

Gruß,
Nils

Geändert von Nils_13 ( 7. Jan 2011 um 17:10 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:26 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz