Mat Random: Zufallszahl, Wiederholung ausschließen

Guten Tag,

Ich habe in javascript per Zufallszahl einen zufälligen Bildwechsel programmiert.

Wie verhindere ich, dass zweimal nacheinander das gleiche Bild geladen wird?
Habe es mit einer while-Schleife versucht, trotzdem wird hin und wieder das gleiche Bild mehrmals geladen.
Ist mein Code oder mein Ansatz falsch?

Vielen Dank vorab!

Hier der von mir verwendete Code:

<html>
<head>
<script language="JavaScript" type="text/javascript">
<!--

//Bild-URL
var URL = "<img src='img/IMG_";

function Bildwechsel(){

//erzeugt eine Zufallszahl "zufall"; 6 Bilder, nummeriert von 1 bis 6
var zufall =  Math.round(Math.random()*5+1);

//Solange der Wert der Zufallszahl mit dem gespeicherten Wert "Wdh" der vorherigen Zahl übereinstimmt,
//soll eine neue Zufallszahl erzeugt werden
while (zufall == Wdh){
var zufall =  Math.round(Math.random()*5+1);
}

//Wenn die Zufallszahl ungleich dem Wert "Wdh" der vorherigen Zahl ist,
//erfolgt die Einbindung der Bild-URL
if (zufall != Wdh){
document.getElementById('erhalteEigenschaften').innerHTML = URL+zufall+".jpg'>"
}

//Speichert zufall für den nächsten Durchlauf
var Wdh = zufall;

//Wiederaufruf der Funktion nach 1s
setTimeout("Bildwechsel()", 1000);
}

//-->
</script>
</head>
<body onload="Bildwechsel()">
<div id="erhalteEigenschaften"></div>
</body>

</html>

  1. Moin

    lass dir mal den Wert von Wdh ausgeben durch alert(Wdh)

    Du wirst bemerken: Wdh ist "undefined", wird ja auch bei jedem Funktionsaufruf neu erzeugt.

    Gruß
    rfb

    1. @rfb:

      Du wirst bemerken: Wdh ist "undefined", wird ja auch bei jedem Funktionsaufruf neu erzeugt.

      Gibt es denn eine Möglichkeit, den ausgegebenen Wert "zufall" in den nächsten Funktionsdurchlauf zu retten?

      @Jürgen:

      Dein Ansatz ist ungeschickt. Schreibe statt dessen die Bildnamen in ein Array und mische dieses. Dann stehen die Namen in zufälliger Reihenfolge im Array und können der Reihe nach gezeigt werden.

      ...wenn ich Dich richtig verstehe, wären die Bilder dann in gemischter, aber nicht zufälliger Reihenfolge.

      @seth

      Ich habe mit Deinem Lösungsansatz experimentiert.
      Leider ohne Erfolg.
      Es fehlt mir nach wie vor die Möglichkeit, den alten Wert von "zufall" mit dem neuen zu vergleichen.

      Danke für Eure Bemühungen!

      MatRandom

      1. hi,

        Du wirst bemerken: Wdh ist "undefined", wird ja auch bei jedem Funktionsaufruf neu erzeugt.

        Gibt es denn eine Möglichkeit, den ausgegebenen Wert "zufall" in den nächsten Funktionsdurchlauf zu retten?

        Ja, beispielsweise in dem du eine globale Variable nutzt.

        Aber was nützt dir _ein_ vorheriger Wert, um Wiederholungen auszuschliessen?

        Dein Ansatz ist ungeschickt. Schreibe statt dessen die Bildnamen in ein Array und mische dieses. Dann stehen die Namen in zufälliger Reihenfolge im Array und können der Reihe nach gezeigt werden.

        ...wenn ich Dich richtig verstehe, wären die Bilder dann in gemischter, aber nicht zufälliger Reihenfolge.

        Unterschied ...?

        Gehe davon aus, dass "Mischen" hier dem gängigen Verständnis von "Mischen" beispielsweise beim Kartenspiel entspricht.

        gruß,
        wahsaga

        --
        /voodoo.css:
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        1. gudn tach!

          Aber was nützt dir _ein_ vorheriger Wert, um Wiederholungen auszuschliessen?

          soweit ich das verstanden habe, geht es nur darum, auszuschliessen, dass zu zwei _aufeinander_folgenden zeitpunkten jeweils dasselbe bild angezeigt wird.

          Gehe davon aus, dass "Mischen" hier dem gängigen Verständnis von "Mischen" beispielsweise beim Kartenspiel entspricht.

          wobei ich es so verstanden habe, dass karten gezogen und auch wieder zurueckgelegt werden sollen.

          prost
          seth

      2. gudn tach!

        @rfb:

        Du wirst bemerken: Wdh ist "undefined", wird ja auch bei jedem Funktionsaufruf neu erzeugt.

        Gibt es denn eine Möglichkeit, den ausgegebenen Wert "zufall" in den nächsten Funktionsdurchlauf zu retten?

        z.b. ueber globale variablen: http://de.selfhtml.org/javascript/sprache/variablen.htm#definieren

        @Jürgen:

        Dein Ansatz ist ungeschickt. Schreibe statt dessen die Bildnamen in ein Array und mische dieses. Dann stehen die Namen in zufälliger Reihenfolge im Array und können der Reihe nach gezeigt werden.

        ...wenn ich Dich richtig verstehe, wären die Bilder dann in gemischter, aber nicht zufälliger Reihenfolge.

        aus auch immer "gemischt" ist...

        @seth

        Ich habe mit Deinem Lösungsansatz experimentiert.
        Leider ohne Erfolg.

        war ein fehler meinerseits. sollte jetzt korrigiert sein.

        Es fehlt mir nach wie vor die Möglichkeit, den alten Wert von "zufall" mit dem neuen zu vergleichen.

        vielleicht hilft dir das beispiel: http://de.selfhtml.org/javascript/objekte/window.htm#set_timeout

        prost
        seth

      3. Hallo Mat,

        ...wenn ich Dich richtig verstehe, wären die Bilder dann in gemischter, aber nicht zufälliger Reihenfolge.

        ich weiß nicht, was Du unter Mischen verstehst, aber stell Dir einen Stapel Bilder vor, den Du wie ein Kartenspiel mischt. Dann sind die Bilder in - meiner Meinung nach - zufälliger Reihenfolge, alle Bilder sind noch da und keins ist doppelt. Wenn Du sie jetzt eins nach dem Anderen von oben abnimmst, hast Du die gewünschte zufällige Reihenfolge.

        Gruß, Jürgen

        1. Hallo Mat,

          ...wenn ich Dich richtig verstehe, wären die Bilder dann in gemischter, aber nicht zufälliger Reihenfolge.

          ich weiß nicht, was Du unter Mischen verstehst, aber stell Dir einen Stapel Bilder vor, den Du wie ein Kartenspiel mischt. Dann sind die Bilder in - meiner Meinung nach - zufälliger Reihenfolge, alle Bilder sind noch da und keins ist doppelt. Wenn Du sie jetzt eins nach dem Anderen von oben abnimmst, hast Du die gewünschte zufällige Reihenfolge.

          Gruß, Jürgen

          Hallo Jürgen,

          Da habe ich Dich wohl falsch verstanden.
          ...
          Ich habe in der Zwischenzeit versucht, eine entsprechende Funktion mit Arrays zu finden, mir ist nicht ganz klar, wie das Mischen vonstatten geht. Hast Du da einen Lösungsansatz für mich?
          Nur zur Sischeheit: Vorraussetzung ist immer noch, dass kein Element zweimal direkt hintereinander geladen wird.

          Gruß, Mat

          1. Hallo Mat,

            Ich habe in der Zwischenzeit versucht, eine entsprechende Funktion mit Arrays zu finden, mir ist nicht ganz klar, wie das Mischen vonstatten geht. Hast Du da einen Lösungsansatz für mich?

            die musst Du auch selbst basteln:

              
            Array.prototype.misch=function() {  
             var l=this.length,t,zi;  
              for(var i=0;i<l;i++) {  
               zi=Math.floor(Math.random()*l);  
               t=this[zi];  
               this[zi]=this[i];  
               this[i]=t;  
              }  
            }  
              
            var a=new Array(1,2,3,4,5,6);  
            alert(a);  
            a.misch();  
            alert(a);  
            
            

            Nur zur Sischeheit: Vorraussetzung ist immer noch, dass kein Element zweimal direkt hintereinander geladen wird.

            probier es aus.

            Gruß, Jürgen

            1. Hallo Jürgen,

              Array.prototype.misch=function() {
              var l=this.length,t,zi;
                for(var i=0;i<l;i++) {
                 zi=Math.floor(Math.random()*l);
                 t=this[zi];
                 this[zi]=this[i];
                 this[i]=t;
                }
              }

              var a=new Array(1,2,3,4,5,6);
              alert(a);
              a.misch();
              alert(a);

                
              Das sieht in der Tat eleganter aus, als mein Ansatz, ich versuche das mal umzusetzen. Das wird wohl etwas dauern; Arrays sind für mich noch Neuland...  
                
              Danke für die Hilfe! Gruß, Mat
              
            2. Tach.

              Array.prototype.misch=function() {
              var l=this.length,t,zi;
                for(var i=0;i<l;i++) {
                 zi=Math.floor(Math.random()*l);
                 t=this[zi];
                 this[zi]=this[i];
                 this[i]=t;
                }
              }

                
              Diese Art des Mischens liefert dir keine wirklich zufällige Verteilung! Einige der n! möglichen Sequenzen sind mit deiner Vorgehensweise wahrscheinlicher als andere.  
                
              Beim richtigen™ Mischen würdest du das Array ebenfalls Schritt für Schritt durchlaufen, dabei aber das aktuelle Element nur mit einem zufällig bestimmten Element tauschen, welches du noch \*nicht\* besucht hast.  
              
              -- 
              Once is a mistake, twice is jazz.
              
              1. Hallo Blaubart,

                Diese Art des Mischens liefert dir keine wirklich zufällige Verteilung! Einige der n! möglichen Sequenzen sind mit deiner Vorgehensweise wahrscheinlicher als andere.

                Beim richtigen™ Mischen würdest du das Array ebenfalls Schritt für Schritt durchlaufen, dabei aber das aktuelle Element nur mit einem zufällig bestimmten Element tauschen, welches du noch *nicht* besucht hast.

                hast Du das mal getestet? Ich habe diesen Algorithmus als "Standard-Algorithmus" zum Mischen gefunden.

                Gruß, Jürgen

                1. Tach.

                  Diese Art des Mischens liefert dir keine wirklich zufällige Verteilung! Einige der n! möglichen Sequenzen sind mit deiner Vorgehensweise wahrscheinlicher als andere.

                  hast Du das mal getestet? Ich habe diesen Algorithmus als "Standard-Algorithmus" zum Mischen gefunden.

                  Das sieht man schon ohne Testen:

                  In jedem Durchlauf erhält man mit deinem Algorithmus eine von n (= Anzahl der Elemente im Array) möglichen Kombinationen. Aus n Druchläufen also insgesamt n^n Möglichkeiten.

                  Stell dir das Mischen nun einfach so vor, daß du aus deinem Originalarray das erste Element nimmst und dieses an beliebige Stelle in einem neuen Array kopierst. Da dieses neue Array am Anfang leer ist, hast du die freie Auswahl d. h. n Möglichkeiten. Für das nächste Element sind es nur noch n-1 Möglichkeiten, für das übernächste n-2, ... Du hast also n! Möglichkeiten, die n Elemente neu anzuordnen.

                  Für alle n > 1 ist n^n > n! und außerdem ist n! nicht in jedem Fall ein ganzzahliges Vielfaches von n^n. Mit deinem Algorithmus generierst du also mehr Anordungen als unterschiedliche Anordnungen existieren. Die überschüssigen Varianten verteilen sich aber nicht gleichermaßen, denn n! teilt wie gesagt n^n nicht immer ohne Rest.

                  --
                  Once is a mistake, twice is jazz.
                  1. Hallo Blaubart,

                    Das sieht man schon ohne Testen:

                    ich leider nicht. Deine Betrachtungen habe ich nicht verstanden.

                    Der von mir gepostete Algorithmus geht doch nur einmal durch das Array und vertauscht der Reihe nach jedes Element mit einem zufällig ermittelten, möglicherweise auch mit sich selbst. Ich sehe da keinen Grund, warum einige Kombinationen nicht möglich sein sollten.

                    Gruß, Jürgen

                    1. gudn tach1

                      Das sieht man schon ohne Testen:

                      ich leider nicht. Deine Betrachtungen habe ich nicht verstanden.

                      es herrscht keine gleichverteilung.

                      am beispiel wird's vielleicht klarer:
                      das ausgangs-array sei array(1,2,3), oder kurz '123', also n=3.

                      0. schritt: (noch nix passiert)
                      123

                      1. schritt: (vertausche erstes element mit einem der drei elemente)
                      123->123
                      123->213
                      123->321
                      alle jeweils gleichwahrscheinlich

                      2. schritt: (vertausche zweites element mit einem der drei elemente)
                      123->123->123
                      123->123->213
                      123->123->132
                      123->213->213
                      123->213->123
                      123->213->231
                      123->321->321
                      123->321->231
                      123->321->312
                      alle jeweils gleichwahrscheinlich. da aber manche kombinationen schon jetzt mehrmals vorkommen und andere seltener, ergibt sich als wahrscheinlichkeit fuer die jeweiligen kombinationen:
                      P(123)=2/9
                      P(213)=2/9
                      P(132)=1/9
                      P(231)=2/9
                      P(321)=1/9
                      P(312)=1/9

                      den 3. schritt lass ich jetzt weg, aber da gleicht es sich nicht wieder komplett aus.
                      es wuerden sich jedenfalls 3^3, also 27 kombinationen ergeben, die nicht alle verschieden sind, denn es kann ja maximal 3!, also 6 kombinationen geben. da 6 kein teiler von 27 ist, _kann_ dieser algorithmus gar keine gleichverteilung ueber alle moeglichen kombinationen erzeugen.

                      prost
                      seth

                      1. Hallo seth_not@home,

                        Das sieht man schon ohne Testen:

                        ich leider nicht. Deine Betrachtungen habe ich nicht verstanden.

                        es herrscht keine gleichverteilung.

                        das habe ich schon verstanden, aber das Warum nicht.

                        am beispiel wird's vielleicht klarer:

                        stimmt. Jetzt habe ich es (glaube ich) verstanden.

                        Jetzt ist die Frage, wird der Algorithmus besser, wenn man ihn öfter laufen lässt? Mitteln sich die Ungleichverteilungen dann wieder weg?

                        Gruß, Jürgen

                        1. Tach.

                          Jetzt ist die Frage, wird der Algorithmus besser, wenn man ihn öfter laufen lässt? Mitteln sich die Ungleichverteilungen dann wieder weg?

                          Nein, nicht für alle Kombinationen. Notwendig ist dieses Mehrfachdurchlaufen auch gar nicht, da mit einer vergleichsweise einfachen Modifikation des Ausgangsalgorithmus ja optimales Mischen erreicht werden kann.

                          --
                          Once is a mistake, twice is jazz.
                          1. Hallo Blaubart,

                            danke für die Tipps, auch an seth. Der Mischer sieht jetzt so aus:

                              
                            Array.prototype.misch=function() {  
                             var l=this.length,t,zi;  
                              for(var i=0;i<l;i++) {  
                               zi=Math.floor(i+Math.random()*(l-i)); // i <= zi < l  
                               t=this[zi];  
                               this[zi]=this[i];  
                               this[i]=t;  
                              }  
                            }
                            

                            Nach ersten Tests für gut befunden.

                            Gruß, Jürgen

  2. Hallo Mat,

    Dein Ansatz ist ungeschickt. Schreibe statt dessen die Bildnamen in ein Array und mische dieses. Dann stehen die Namen in zufälliger Reihenfolge im Array und können der Reihe nach gezeigt werden.

    Gruß, Jürgen

  3. gudn tach!

    Wie verhindere ich, dass zweimal nacheinander das gleiche Bild geladen wird?

    z.b. ueber eine globale variable.

    Hier der von mir verwendete Code:
    [...]
    //Speichert zufall für den nächsten Durchlauf
    var Wdh = zufall;

    iirc legst du damit bloss eine lokale variable an.

    ich wuerde mal folgendes probieren.

      
    var wdh = 0;  
    function Bildwechsel(){  
      for(var zufall = wdh; zufall == wdh; zufall = Math.round(Math.random()*5+1));  
      document.getElementById('erhalteEigenschaften').innerHTML = URL+zufall+".jpg'>"  
      setTimeout("Bildwechsel()", 1000);  
    }
    

    ich bin allerdings nicht mehr so bewandert in js. kann sein, dass ich falsch liege.

    prost
    seth

    1. gudn tach!

      ich wuerde mal folgendes probieren.

      nein! das war kaese!

      die zeile
        wdh=zufall;
      hat noch gefehlt.

        
      var wdh = 0;  
      function Bildwechsel(){  
        for(var zufall = wdh; zufall == wdh; zufall = Math.round(Math.random()*5+1));  
        wdh=zufall;  
        document.getElementById('erhalteEigenschaften').innerHTML = URL+zufall+".jpg'>"  
        setTimeout("Bildwechsel()", 1000);  
      }
      

      prost
      seth

      1. Ja, sehr gut!
        Das läuft.
        Vielen herzlichen Dank!!!

        Gruß, Mat

      2. gudn tach!

        ich wuerde mal folgendes probieren.

        nein! das war kaese!

        die zeile
          wdh=zufall;
        hat noch gefehlt.

        var wdh = 0;
        function Bildwechsel(){
          for(var zufall = wdh; zufall == wdh; zufall = Math.round(Math.random()*5+1));
          wdh=zufall;
          document.getElementById('erhalteEigenschaften').innerHTML = URL+zufall+".jpg'>"
          setTimeout("Bildwechsel()", 1000);
        }

        
        >   
        > prost  
        > seth  
          
        Eine Frage hätte ich doch noch:  
        Code-Zeile:  
        " for(var zufall = Wdh; zufall == Wdh; zufall = Math.round(Math.random()\*5+1));"  
          
        Worin besteht der inhaltliche Unterschied zwischen  
        "var zufall = Wdh" und "zufall == Wdh"?  
          
        Gruß, Mat
        
        1. Tach.

          Worin besteht der inhaltliche Unterschied zwischen
          "var zufall = Wdh" und "zufall == Wdh"?

          Das eine ist eine http://de.selfhtml.org/javascript/sprache/operatoren.htm#zuweisung@title=Wertezuweisung, das andere ein http://de.selfhtml.org/javascript/sprache/operatoren.htm#vergleich@title=Vergleich.

          --
          Once is a mistake, twice is jazz.
  4. Hallo Mat,

    var zufall =  Math.round(Math.random()*5+1);

    habe ich gerade erst gesehen: mit round bekommst Du keine Gleichverteilung. Nimm lieber floor oder ceil.
    Siehe hierzu auch: http://www.j-berkemeier.de/test/zuftest.html

    Gruß, Jürgen

    1. gudn tach!

      var zufall =  Math.round(Math.random()*5+1);

      habe ich gerade erst gesehen: mit round bekommst Du keine Gleichverteilung. Nimm lieber floor oder ceil.

      jein. der punkt, den du angesprochen hast, ist zwar wichtig zu beachten, deswegen habe ich dein posting auch als hilfreich bewertet. allerdings kann es leicht missverstanden werden, wenn man sagt "mit round bekommst du keine gleichverteilung".

      mit
        var zufall = Math.round(Math.random()*6+.5);
      kann man naemlich durchaus genauso gut wuerfeln wie mit
        var zufall = Math.floor(Math.random()*6+1);.

      Siehe hierzu auch: http://www.j-berkemeier.de/test/zuftest.html

      da waere es entsprechend

      function JB_random_r(min,max) {
        return(Math.round(min-.5+Math.random()*(max-min+1)));
      }

      prost
      seth

      1. Hallo seth,

        var zufall = Math.round(Math.random()*6+.5);
        kann man naemlich durchaus genauso gut wuerfeln wie mit
          var zufall = Math.floor(Math.random()*6+1);.

        damit hast Du die Umrechnung von round nach ceil/floor und umgekehrt. Unter Fortran IV gab es noch kein Runden und bei der Zuweisung von Fließkommazahlen auf Integer wurden die Nachkommastellen einfach abgeschnitten. Durch die Addition von 0.5 konnten wir aber auch damals schon runden.

        Gruß, Jürgen

        1. gudn tach!

          var zufall = Math.round(Math.random()*6+.5);
          kann man naemlich durchaus genauso gut wuerfeln wie mit
            var zufall = Math.floor(Math.random()*6+1);.

          damit hast Du die Umrechnung von round nach ceil/floor und umgekehrt.

          eben; obgleich erstmal nur ohne ceil. round/floor/ceil sind halt nix grossartig verschiedenes, weswegen ich deine aussage wie gesagt nur praezisieren/relativieren wollte. die _funktionen_ sorgen nicht fuer _eine_ bestimmte verteilung, sondern je nach anwendung/definitionsbereich fuer verschiedene.

          prost
          seth

  5. Moin!

    Wie wäre es hiermit? Beim ersten Durchlauf hast du doch die Auswahl zwischen 6 Bildern, danach nur noch zwischen 5. Also wird im 2ten und folgenden nur noch eine Zufallszahl von 2-6 ermittelt. War sie zufällig dieselbe wie zuvor, wird stattdessen die 1 genommen. Dies ist ein spezieller Fall einer "Mischroutine" bei der Du in einem Array von Größe n einfach alle möglichen erlaubten Werte speicherst. Danach würfelst Du in n Durchläufen einen Index im Bereich von "durchlauf" bis n. Das gefundene Array Element tauscht Du mit dem Element an Position "durchlauf". Am Ende ist eine gemischte Folge im Array.

    <html>  
    <head>  
    <script language="JavaScript" type="text/javascript">
    
      
    <!--  
      
    //Bild-URL  
    var URL = "<img src='img/IMG_";  
    var wdh=0; // speichert die letzte Bildnummer  
    var min=1; // 1 für den ersten Durchlauf, danach 2  
    var max=6;  
      
    function Bildwechsel(){  
      
    //erzeugt eine Zufallszahl "zufall"; 6 Bilder, nummeriert von 1 bis 6  
    var zufall =  min+Math.floor(Math.random()*(max-min)); // 1-6 gleichverteilt bzw. später 2-6  
      
    if ( zufall == wdh ) {  
     zufall= 1;  
    }  
      
    document.getElementById('erhalteEigenschaften').innerHTML = URL+zufall+".jpg'>"  
      
    //Speichert zufall für den nächsten Durchlauf  
    wdh = zufall;  
    min = 2;  
      
    //Wiederaufruf der Funktion nach 1s  
    setTimeout("Bildwechsel()", 1000);  
    }  
      
    //-->  
    
    
    </script>  
    </head>  
    <body onload="Bildwechsel()">  
    <div id="erhalteEigenschaften"></div>  
    </body>  
      
    </html>
    

    -- Skeeve

    1. gudn tach!

      //erzeugt eine Zufallszahl "zufall"; 6 Bilder, nummeriert von 1 bis 6
      var zufall = min+Math.floor(Math.random()*(max-min)); // 1-6 gleichverteilt bzw. später 2-6

      da fehlt "+1", weil "random" zahlen aus [0,1) liefert (wenn selfhtml recht hat).

      also:

      var zufall = min+Math.floor(Math.random()*(max-min+1));

      ansonsten ist diese methode der urspruenglichen bzw. der korrigierten (https://forum.selfhtml.org/?t=142119&m=923435) ueberlegen, weil sie keine haessliche potenzielle endlos-schleife enthaelt.

      prost
      seth

      1. Moin!

        da fehlt "+1", weil "random" zahlen aus [0,1) liefert (wenn selfhtml recht hat).

        Korrekt. Das ist mal wieder eines dieser (Zitat mein Informatik Professor) "nicht-trivialen +/- 1 Probleme".

        -- Skeeve