Anzeige
Tutorialbeschreibung

Javascript und Ajax - Zufallszahlen erstellen

Javascript und Ajax - Zufallszahlen erstellen

In Kapitel 6 dreht sich alles um den Zufall. Du erfährst wie du Zufallszahlen generieren und verarbeiten kannst. Das Ende wird mit zwei Praxisbeispielen abgerundet, somit kommst du zu deinem ersten richitgen Script.


Das nun folgende Tutorial ist ein Auszug aus der 7. Auflage des Buches: JavaScript und Ajax von Christian Wenz.

Kapitel 6 Zufall

Wenn Sie den Zufallsbegriff streng mathematisch auslegen, ist ein Computer gar nicht in der Lage, einen »Zufall« zu produzieren. Der Grund liegt auf der Hand: Ein Computer kann keine Zufallszahl aus irgendwelchen (tatsächlichen) Stromschwankungen ermitteln, sondern muss diese auf Basis eines Algorithmus berechnen.

Dennoch ist ein Computer in der Lage, relativ zufällige Zahlenfolgen zu produzieren. Es gibt eine Reihe von Methoden, um zufällige Zahlenfolgen zu bestimmen. Das Problem bei solchen Methoden ist jedoch immer der Startwert.

Wir stellen in diesem Kapitel einige Möglichkeiten vor, wie Sie selbst Zufallszahlen erzeugen können. Als Nächstes programmieren wir einige Hilfsfunktionen, die Ihnen einen schnellen Zugriff auf die Zufallszahlen ermöglichen. Am Ende des Kapitels zeigen wir noch einige Beispielapplikationen, die mit Zufallszahlen (und JavaScript) erstellt werden können.

Fast die komplette benötigte Funktionalität steckt in dem Math-Objekt von JavaScript, unter anderem die Ermittlung einer Zufallszahl und das Runden von Zahlen.


6.1 Zufallszahlen erstellen

Bei der Ermittlung einer Zufallszahl haben Sie die freie Auswahl: Entweder Sie bedienen sich bei den mitgelieferten Funktionalitäten, oder Sie programmieren Ihren eigenen Zufallsgenerator.


6.1.1 JavaScript-Zufallszahlen  

Seit den Anfängen von JavaScript gibt es die Methode Math.random(), die eine (ziemlich) zufällige Zahl zwischen 0 und 1 zurückliefert. Die Browser bedienen sich hierbei eines internen Algorithmus. Als Startwert für diesen Algorithmus verwenden die Browser veränderliche Daten wie beispielsweise die aktuelle Uhrzeit sowie (bei manchen Algorithmen) benutzerspezifische Daten wie etwa den freien Speicher auf der Festplatte oder die MAC-Adresse der Netzwerkkarte.

Es ist nicht weiter schlimm, dass Math.random() eine Fließkommazahl zwischen 0 und 1 zurückliefert. Wenn Sie eine ganzzahlige Zufallszahl innerhalb eines bestimmten Bereichs haben möchten, können Sie aus der Fließkommazahl eine ganze Zahl ermitteln, behalten dabei aber das Zufallsmoment bei (mehr dazu später im Kapitel).


6.1.2 HP-Verfahren  

Das HP-Verfahren ist nach der amerikanischen Firma Hewlett-Packard benannt, die vor allem für ihre Tintenstrahl- und Laserdrucker bekannt ist. Die Entwicklungsabteilung der Firma hat der Legende nach den Algorithmus entwickelt (sie empfiehlt ihn zumindest vehement und baut ihn angeblich auch in die eigenen Produkte ein).

Der Algorithmus funktioniert folgendermaßen:

gpBilder
 
Man beginne mit einer Zahl zwischen 0 und 1.
gpBilder
 
Man addiere zu dieser Zahl die Kreiszahl p (etwa 3,14159265...).
gpBilder
 
Das Ergebnis potenziere man mit 8 (umgangssprachlich: Das Ergebnis »hoch 8« nehmen).
gpBilder
 
Der Nachkommaanteil des Ergebnisses ist die nächste Zufallszahl.
gpBilder
 
Mit dem Nachkommateil starte man den Algorithmus erneut, um eine weitere Zufallszahl zu erhalten.

Es ist mathematisch nachgewiesen, dass dieser Algorithmus die (mathematischen) Bedingungen für einen Zufallsgenerator erfüllt; die entstehende Zahlenfolge ist tatsächlich zufällig.

Was uns fehlt, ist ein Startwert zwischen 0 und 1. Mit Math.random() ließe sich einer bestimmen, aber das würde die Grundidee unseres Vorgehens konterkarieren. Stattdessen setzen wir hier eine andere, weitere Methode zur Bestimmung einer Zufallszahl ein – auch wenn die nicht ganz so geeignet ist wie beispielsweise Math.random().

Mit dem Date-Objekt aus dem vorherigen Kapitel können Sie auf das aktuelle Datum und die aktuelle Uhrzeit zugreifen. Die Methode getTime() liefert die so genannte Epochenzeit zurück. Das ist die Anzahl der seit dem 1. Januar 1970, Mitternacht, verstrichenen Millisekunden.

Diese Zahl ist mehr oder wenig zufällig und damit ein besonders geeigneter Zufallswert für unsere Zwecke. Werfen wir einen Blick auf einen dieser Datumswerte: Rufen Sie dazu in Ihrem Browser die Pseudo-URL javascript:alert(new Date().getTime()) auf.

Bilder

Abbildung 6.1     Das ist tatsächlich eine Uhrzeit.

Als Startwert benötigen Sie aber eine Zahl zwischen 0 und 1. Aus diesem Grund müssen Sie vor die lange Zahl »0.« schreiben, um diese möglichst schnell in eine Fließkommazahl umzuwandeln.

Bevor der Zeitwert in eine Fließkommazahl umgewandelt wird, ist noch eine weitere Überlegung erforderlich. Wenn Sie die Zufallszahlengenerierung mehrmals hintereinander aufrufen, ähneln sich die ersten Zufallszahlen sehr, denn der Startwert ändert sich dort erst circa in der achten Nachkommastelle. Aus diesem Grund ist es eine gute Idee, das Ergebnis von getTime() umzudrehen, also die letzte Ziffer als erste Nachkommastelle zu verwenden, die vorletzte Ziffer als zweite Nachkommastelle und so weiter. Da viele Browser als letzte Ziffer von getTime()immer »0« liefern, ignorieren wir die letzte Ziffer vollständig.

var t = new Date().getTime();
var t2 = "";
for (var i=2; i<=t.length; i++) {
   t2 += t.charAt(t.length-i);
}
eval("var z = 0." + t2);

Am Ende enthält die Variable z eine (recht zufällige) Zahl zwischen 0 und 1.

Nun kann der Rest des Algorithmus programmiert werden: Zur Zahl wird p hinzuaddiert (p steht bei JavaScript in der Eigenschaft Math.PI zur Verfügung):

z += Math.PI;

Dann wird das Ergebnis mit 8 potenziert – mit der Methode pow() des Math-Objekts:

z = Math.pow(z, 8);

Die neue Zufallszahl ist dann der Nachkommaanteil des Ergebnisses – das ermitteln Sie mit der Methode floor() des Math-Objekts:

z -= Math.floor(z);

Das Gegenstück zu floor() ist die Methode ceil() – die rundet nämlich ab.

Die folgende Funktion fasst dieses Vorgehen zusammen. Die jeweils letzte Zufallszahl wird in einer globalen Variablen gespeichert, damit sie beim nächsten Aufruf der Funktion wieder als Startwert verwendet werden kann.

var zufall_hp_zahl = 0;
function zufall_hp() {
   if (zufall_hp_zahl == 0) {
      var t = new Date().getTime().toString();
      var t2 = "";
      for (var i=2; i<=t.length; i++) {
         t2 += t.charAt(t.length-i);
      }
      eval("zufall_hp_zahl = 0." + t2 + ";");
   }
   zufall_hp_zahl += Math.PI;
   zufall_hp_zahl = Math.pow(zufall_hp_zahl, 8);
   zufall_hp_zahl -= Math.floor(zufall_hp_zahl);
   return zufall_hp_zahl;
}


6.1.3 Datumswert 
topBilder

Betrachten Sie noch einmal, was der Browser bei der Eingabe der Pseudo-URL javascript:alert(new Date().getTime()) ausgibt (siehe auch Abbildung 6.1). Sie erhalten eine recht lange Zahl, die offensichtlich immer auf 0 endet. Das hat mit den browserinternen Abläufen zu tun sowie mit der Unfähigkeit, auf die Millisekunde genau zu messen. Für Sie entscheidend ist aber, dass Sie diesen Wert durch 10 teilen sollten, um eine »zufälligere« Zahl zu erhalten:

var z = new Date().getTime();
z = Math.round(z / 10);

Wenn Sie nun eine ganzzahlige Zufallszahl benötigen, gibt es eine einfache Möglichkeit, diese zu ermitteln. Verwenden Sie die Modulo-Rechnung!

Unter Modulo versteht man den Rest, den eine Division liefert. Unter JavaScript ist der Modulo-Operator %. 15  % 7 liefert als Ergebnis 1, denn bei der Division von 15 durch 7 bleibt als Rest 1 übrig (15 = 2 × 7 + 1).

Ein wenig mathematischer: Der Rest bei einer Division durch N ist eine Zahl zwischen 0 und N-1. Wenn Sie also eine Zufallszahl zwischen 0 und N haben möchten, können Sie wie folgt vorgehen:

var z = new Date().getTime();
z = Math.round(z / 10);
z %= n;

Die folgende Funktion setzt dieses Vorgehen allgemein für die Aufgabenstellung »berechne eine Zufallszahl zwischen a und b« um.

function zufall_datum(a, b) {
   var spanne = b – a + 1; // Länge des Intervalls
   var z = new Date().getTime();
   z = Math.round(z / 10);
   z %= spanne;  // z ist zwischen 0 und spanne-1
   z += a; // z ist nun zwischen a und b
   return z;
}

6.2 Hilfsfunktionen 
topBilder

Sie wissen nun, wie Sie Zufallszahlen zwischen 0 und 1 generieren können (von der Funktion zufall_datum() einmal abgesehen); für weitere Funktionalitäten benötigen Sie aber noch einige weitere Funktionen. Natürlich können Sie bei jeder neuen Anwendung dieses Problem erneut lösen, aber der Sinn dieses Buches ist es ja unter anderem, Ihnen diese Arbeit abzunehmen.


6.2.1 Zufallszahl aus einem Bereich 
topBilder

Math.random() liefert eine Zufallszahl zwischen 0 und 1 zurück. Oft benötigen Sie jedoch eine ganzzahlige Zufallszahl. Dazu müssen Sie die Zahl umrechnen.

Im Folgenden wollen wir etwas machen, bei dem jeder Mathematiker nur den Kopf schütteln würde: Wir wollen mit Intervallen rechnen. Dazu verwenden wir die folgende Intervallschreibweise: ]a, b[ steht für eine Zahl, die zwischen a und b liegt, jedoch weder a noch b ist.

Nun geht es los: Wir wollen eine Zahl ermitteln, die im Intervall ]a, b] liegt. Beginnen wir mit den bereits bekannten Funktionen: Math.random() oder zufall_hp() oder zufall_datum() liefern eine Zahl zwischen 0 und 1 zurück:

]0, 1[

Diese Zahl wollen wir mit b – a + 1 multiplizieren. Also müssen die Grenzen des Intervalls mit diesem Faktor multipliziert werden:

]0, b – a + 1[

Dann wird zur Zahl a hinzugezählt:

]a, b+1[

Sie haben nun eine Zahl erhalten, die größer als a und auf jeden Fall kleiner als b+1 ist. Wenn Sie diese Zahl abrunden, erhalten Sie eine ganze Zahl, die zwischen (jeweils einschließlich) a und b liegt.

Dieser Algorithmus lässt sich leicht in JavaScript umsetzen:

function zufall_intervall(

a, b) { var z = Math.random(); z *= (b – a + 1); z += a; return (Math.floor(z)); }

Wenn Sie statt Math.random() lieber auf zufall_hp() setzen möchten, müssen Sie die Funktion lediglich an einer Stelle verändern:

function zufall_intervall_hp(a, b) { var z = zufall_hp(); z *= (b – a + 1); z += a; return (Math.floor(z)); }

 

6.3 Anwendungsbeispiele 
topBilder

Mithilfe der in diesem Kapitel vorgestellten Funktionen können Sie nun so viele Zufallszahlen erzeugen, wie Sie möchten. Sollte Ihnen zufällig kein Verwendungszweck für diese Zahlen einfallen, finden Sie im Folgenden zwei Anwendungsbeispiele.


6.3.1 Lottozahlen  

Im deutschen Lottoblock werden zweimal pro Woche sechs (Zufalls-)Zahlen aus 49 sowie eine Zusatzzahl gezogen; in anderen Ländern ist das Vorgehen ähnlich, wenngleich sich die Zahlen leicht ändern. Ignorieren wir die Zusatzzahl, dann bleibt nur noch das Problem, sechs verschiedene Zahlen zu ziehen. Das geht aber recht einfach: Die Zahlen werden in einem Array gespeichert. Nach jedem Ziehen einer Zahl wird nachgesehen, ob die Zahl bereits im Array vorhanden ist. Falls nein, wird sie ins Array eingefügt:

var lotto; // die Lottozahlen
// ...
var zahl = zufall_intervall(1, 49);
for (var i=0; i < lotto.length; i++) {
   if (lotto[i] == zahl) {
      continue;
   }
}
lotto[lotto.length] = zahl;

Wie Sie sehen, fehlt hier noch ein wenig: Die Verwendung von continue deutet an, dass eine Schleife zum Einsatz kommt. Und in der Tat: In einer while-Schleife werden so lange Zahlen gezogen, bis das Array »voll« ist, also in unserem Beispiel sechs Elemente enthält:

while (lotto.length < 6) {
   // ...
}

Das birgt natürlich ein wenig Gefahrenpotenzial in sich: Wenn Sie die Werte ungünstig wählen (etwa: sechs verschiedene Zufallszahlen zwischen eins und fünf), erhalten Sie eine Endlosschleife. Achten Sie also darauf, welche Grenzen Sie angeben!

Hier folgt das komplette Listing:

<html>
<head>
<title>Lottozahlen</title>
<script type="text/javascript">
function zufall_intervall(a, b) {
   var z = Math.random();
   z *= (b – a + 1);
   z += a;
   return (Math.floor(z));
}
</script>
</head>
<body>
<h1>Lottozahlen</h1>
<script type="text/javascript"><!--
var lotto = [];
while (lotto.length < 6) {
   var zahl = zufall_intervall(1, 49);
   for (var i=0; i < lotto.length; i++) {
      if (lotto[i] == zahl) {
         continue;
      }
   }
   lotto[lotto.length] = zahl;
}

document.write(lotto.toString());
//--></script>
</body>
</html>

Zum Vergleich noch das Listing für den Einsatz des HP-Algorithmus zur Generierung der Zufallszahlen:

<html>
<head>
<title>Lottozahlen</title>
<script type="text/javascript">
var zufall_hp_zahl = 0;
function zufall_hp() {
   if (zufall_hp_zahl == 0) {
      var t = new Date().getTime().toString();
      var t2 = "";
      for (var i=2; i<=t.length; i++) {
         t2 += t.charAt(t.length-i);
      }
      eval("zufall_hp_zahl = 0." + t2 + ";");
   }
   zufall_hp_zahl += Math.PI;
   zufall_hp_zahl = Math.pow(zufall_hp_zahl, 8);
   zufall_hp_zahl -= Math.floor(zufall_hp_zahl);
   return zufall_hp_zahl;
}
function zufall_intervall_hp(a, b) {
   var z = zufall_hp();
   z *= (b – a + 1);
   z += a;
   return (Math.floor(z));
}
</script>
</head>
<body>
<h1>Lottozahlen</h1>
<script type="text/javascript"><!--
var lotto = new Array();
while (lotto.length < 6) {
   var zahl = zufall_intervall_hp(1, 49);
   for (var i=0; i < lotto.length; i++) {
      if (lotto[i] == zahl) {
         continue;
      }
   }
   lotto[lotto.length] = zahl;
}

document.write(lotto.toString());
//--></script>
</body>
</html>

Bilder

Abbildung 6.2     Die zufällig ermittelten Lottozahlen


6.3.2 Zufallsbanner 
topBilder

Eine häufige Anwendung besteht darin, einen von mehreren Textbausteinen einzublenden. Stellen Sie sich vor, Sie haben einen Satz von zehn Werbebannern, die alle gleichmäßig oft aufgerufen werden sollen. Dies ist ein Paradebeispiel für die Anwendung von Zufallszahlen.

An diesem Beispiel soll eine mögliche Zusammenarbeit zwischen Skriptprogrammierern, den Skripten in diesem Buch und einem HTML-Programmierer demonstriert werden.

Von der Konzeption her wäre es möglich, eine Funktion zu erstellen, die als Parameter ein Array mit Links und ein (gleich sortiertes Array) mit den zugehörigen Linktexten erwartet. Bei grafischen Bannern muss anstelle der Linktexte ein Array mit den Namen der Bannergrafiken erstellt werden. Dies ist jedoch etwas schwierig und umständlich.

Stattdessen soll hier ein anderer Weg gewählt werden. Der Code zur Auswahl der einzelnen URLs und der zugehörigen Linktexte wird direkt in die HTML-Seite integriert. Von den Skripten aus diesem Kapitel wird lediglich eine Funktion zur Zufallszahlengenerierung eingesetzt. Damit dieses Beispiel bei Ihnen funktioniert, müssen Sie zunächst die im Code verwendeten Banner erstellen.

Als Zufallsfunktion bieten sich hier zufall_intervall(a, b) oder zufall_intervall_hp(a, b) an:

<html>
<head>
<title>Zufallsbanner</title>
<script type="text/javascript"><!--
function zufall_intervall(a, b) {
  var z = Math.random();
  z *= (b – a + 1);
  z += a;
  return (Math.floor(z));
}

// Variablen mit URLs und Linktexten
var urls = new Array();
var texte = new Array();
var grafiken = new Array();

urls[urls.length] = "http://www.microsoft.de/";
texte[texte.length] = "Microsoft Deutschland";
grafiken[grafiken.length] = "microsoft.png";
urls[urls.length] = "http://www.mozilla.com/";
texte[texte.length] = "Mozilla Foundation";
grafiken[grafiken.length] = "mozilla.png";

urls[urls.length] = "http://www.opera.com/";
texte[texte.length] = "Opera Browser";
grafiken[grafiken.length] = "opera.png";

var zufall = zufall_intervall(0, urls.length – 1);
var url = urls[zufall];
var text = texte[zufall];
var grafik = grafiken[zufall];
//--></script>
</head>
<body>
<h1>Zufallsbanner</h1>
<script type="text/javascript"><!--
document.write("<a href="" + url + "">");
document.write("<img src="" + grafik +"" border="0" / />");
// alternativ für Textlinks: document.write(text);
document.write("</a>");
//--></script>
</body>
</html>

Im oben dargestellten Listing finden Sie parallel dazu noch den Code für Textlinks. Anstelle der Ausgabe der Grafik

document.write("<img src="" + grafik +"" border="0" />");

muss der entsprechende Text für den Link ausgegeben werden:

document.write(text);

Das Tutorial ist ein Auszug aus der 7. Auflage des Buches von Christian Wenz:

JavaScript und Ajax - Das umfassende Handbuch
Galileo Computing, 853 Seiten, 8. aktualisierte Auflage

Die Veröffentlichung des Kapitels erfolgt mit freundlicher Genehmigung von Galileo Press.

Mehr Informationen zum aktualisierten Fachbuch für Webentwickler gibt es hier: JavaScript und Ajax
 
Alle Kapitel des Buches:
1 Grundlagen
2 JavaScript-Praxis
3 Professionelles JavaScript
4 Web 2.0 und Ajax
5 Kommunikation
6 Serverseitige Programmierung
7 Sicherheit
8 Praxis
9 Anhang
Bilder


 

DVD-Werbung
Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von Pictureboy28
Portrait von Lugo
  • 22.04.2010 - 12:11

Ich soll ma gerade ein script für mein Studium schreiben.... nu schau ich mir dieses Kapietel an und bin noch verwirrter ^^

Portrait von haroXX
  • 05.04.2008 - 19:05

ehrlich gesagt versteh ich einige sachen nicht ;o

x
×
×