Lotto 6 aus 45 in PHP →

Aufgabe

Erstelle eine Internetseite, die einen Quicktipp des österreichischen Lotto 6 aus 45 ausgibt. Dies ist eine Übungsaufgabe, die ein Verständnis für

  • Arrays
  • Schleifen

in PHP vermitteln soll.

Was gibt es darüber zu wissen?

  • Beim österreichischen Lotto 6 aus 45 werden aus einem Pool von 45 Zahlen 6 zufällig gezogen.
  • Daraufhin wird eine sogenannte Zusatzzahl gezogen.
  • Die 6 gezogenen Zahlen können also aufsteigend sortiert werden, die Zusatzzahl bleibt jedoch immer für sich stehen.

Ablauf

In einfache Worte gefasst, ohne dabei auf die Möglichkeiten einer spezifischen Programmiersprache einzugehen:

  • Ziehe aus einer Menge im Wertebereich 1 bis 45 eine zufällige Zahl.
  • Speichere die gezogene Zahl in einem Zwischenbehälter.
  • Wiederhole dies noch fünfmal (in Summe also sechs Ziehungen).
  • Sortiere die gezogenen Zahlen im Zwischenbehälter aufsteigend.
  • Ziehe eine weitere Zahl aus dem Wertebereich 1 bis 45; dies ist die Zusatzzahl.

Programmstruktur

Nun gibt es verschiedene Ansätze, um dies in PHP zu lösen.

For-Loop für die Zielmenge

  • Von 1 bis 6: ziehe.
  • Solange Zahl schon in der Menge der gezogenen Zahlen: ziehe nochmal.
  • Am Ende ziehe eine weitere Zahl, die noch nicht in der Menge der gezogenen Zahlen ist - dies ist die Zusatzzahl.
  • Zahlen ausgeben.

Dies ist wohl am häufigsten zu Beginn der Programmierung gewählte Herangehensweise. Sie folgt der Denkweise des Ablaufs in der realen Welt, dem Wählen von beschrifteten Kugeln aus einer Urne. Jedoch stellt sich bald heraus, dass es einige Hürden - wie etwa das evaluieren, ob eine Zahl bereits gezogen wurde - gibt.

Der Code ist absolut hässlich, aber er scheint zu tun, was er soll.

// Variables used throughout the programm
// CONSTANTS
define( "LOWEREND",       1   );
define( "UPPEREND",       45  );
define( "NUMBEROFPICKS",  6   );

// vars
$numbersPicked = array();
$running = true;
$currentPick = 0;

for($i=1; $i < NUMBEROFPICKS; $i++) {
    // 
    $running = true;
    echo "<b>Entering Loop $i of " . NUMBEROFPICKS . "</b><br><br>";

    do {
        // Pick a number
        $currentPick = random_int(LOWEREND, UPPEREND);

        if(! isset($numbersPicked[0])) {
            echo "array not set yet<br>";
            echo "setting array at pos 0 to $currentPick<br>";

            $pickedSize = 0;
            $numbersPicked[0]=$currentPick;
        } else {
            $pickedSize = count($numbersPicked);
        }

        for ($j=0; $j < $pickedSize  ; $j++) {
            echo "j = " . $j . "<br>"; 
            echo "size of array " . (count($numbersPicked)) . "<br>";
            if($numbersPicked[$j] == $currentPick){
                echo "<div style='color:red;'>$currentPick wurde bereits gezogen.</div><br>";
                break;
            } else {
                echo "$currentPick zahl wird zu den Treffern hinzugefügt.<br>";
                array_push($numbersPicked, $currentPick);
                $running = false;
                break;
            } // endif
        } // end for each pick

    } while ($running == true);

} // end for loop (1..6)

echo "<p>Folgende Zahlen wurden gezogen:</p>";
echo "<ul>";
sort($numbersPicked);
foreach ($numbersPicked as $number) {
    echo "<li>$number</li>";
}
echo "</ul>";
echo "<p>Es wurde keine Zusatzzahl gezogen.</p>";

Schleife (While-Loop) bis alle Aufgaben erledigt sind

Der Ansatz setzt voraus, dass man schon einen gewissen Überblick der Möglichkeiten von Arrays und Schleifen besitzt. Bei diesem Ansatz werden zu Programmbeginn einige Vorgaben definiert, die erfüllt sein müssen, bevor der Programmablauf abgeschlossen werden kann.

  • Anlegen eines Arrays für den Wertebereich 1 bis 45.
  • Anlegen eines Arrays für die Zielmenge. Der Array hat 6 Felder, diese werden vorbereitet, aber sind noch nicht mit Werten gefüllt, bzw. erhalten 0 als Markierung für „ungültig“.
  • Solange (While) der Array für die Zielmenge nicht vollständig befüllt ist (es gibt also noch Werte mit 0):
  1. Ziehe eine zufällige Zahl aus dem Wertebereich.
  2. Prüfe, ob die gezogene Zahl bereits vorhanden ist.
  3. Wenn nein, füge sie der Zielmenge hinzu.

Dieser Ansatz ist dem ersten sehr ähnlich, jedoch ist der Ablauf etwas anders geschachtelt. Dies mag der Denkweise einiger entgegenkommen.

Verändern des Wertebereichs nach dem Ziehen

Bei diesem Lösungsansatz werden die Arrays für den Wertebereich und die Zielmenge ebenfalls schon zu Programmbeginn definiert. Auch die Ziehung einer Zahl aus dem Wertebereich erfolgt wie gehabt zufällig. Allerdings kommt jetzt eine Änderung:

Um nicht nach jedem Zug überprüfen zu müssen, ob die Zahl schon in der Zielmenge vorhanden ist, wird die gezogene Zahl einfach aus dem Wertebereich entfernt. Somit kann Sie bei der nächsten Ziehung schlichtweg nicht mehr zur Verfügung stehen. Der Ablauf kann also wie folgt festgehalten werden:

  • Anlegen eines Arrays für den Wertebereich 1 bis 45.
  • Anlegen eines Arrays für die Zielmenge. Der Array hat 6 Felder, diese werden vorbereitet, aber sind noch nicht mit Werten gefüllt, bzw. erhalten 0 als Markierung für „ungültig“.
  • Solange (While) der Array für die Zielmenge nicht vollständig befüllt ist (es gibt also noch Werte mit 0):
  1. Ziehe aus dem Wertebereich eine zufällige Zahl.
  2. Entferne die Zahl aus dem Wertebereich.
  3. Füge die Zahl der Zielmenge hinzu.

Dieser Ansatz hat nur wenige Voraussetzungen:

  • Zu wissen, wie man aus dem Array ein Feld zufällig auswählt (z.B. über die Größe des Array = Anzahl der Felder, unabhängig vom Wert im Feld).
  • Zu wissen, wie man ein Feld mit einem bestimmten Wert in einem Array findet.
  • Zu wissen, wie man ein Feld aus einem Array entfernt.

Die Programmiersprache die Arbeit erledigen lassen

Sobald man einige Erfahrung in einer Programmiersprache gesammelt hat, merkt man, dass auch andere bereits die gleichen oder zumindest ähnliche Aufgabenstellungen zu bewältigen hatten. Daher gibt es in vielen Programmiersprachen die benötigten Funktionalität entweder bereits in der mit der Programmiersprache ausgelieferten Standardbibliothek oder Module/Bibliotheken von Dritten. Im Falle der Lottoziehung mit PHP kann auch wie folgt vorgegangen werden:

  • Anlegen des Arrays für den Wertebereich 1 bis 45.
  • Mit einer Funktion auf einmal 6 zufällige Zahlen des Array ziehen.
  • Die Zahlen an der Stelle 1 bis 6 bilden die reguläre Ziehung.
  • Die Zahlen an der Stelle 1 bis 6 in die Zielmenge überführen und sortieren.
  • Zielmenge von Basismenge abziehen (Differenz).
  • Aus der bleibenden Menge eine Zusatzzahl wählen.

Ohne zu viel der fertigen Lösung (siehe weiter unten) preisgeben zu wollen:

// Variables used throughout the programm
// CONSTANTS
define( "LOWEREND",       1   );
define( "UPPEREND",       45  );
define( "NUMBEROFPICKS",  6   );

// vars and containers
$allNumbers = array();
$numbersPicked = array();
$extraNum = 0;

// Fill the Array with our target numbers
for($i=LOWEREND;$i<=UPPEREND;$i++) {
    $allNumbers[$i] = $i;
}

// Pick numbers from the total numbers and sort them
$numbersPicked = array_rand(array_flip($allNumbers),NUMBEROFPICKS);
sort($numbersPicked);

// make a diff - now only valid numbers are still in the container
$restArrayForExtraNum = array_diff($allNumbers, $numbersPicked);    

// we pick an extra number
$extraNum = array_rand(array_flip($restArrayForExtraNum),1); // just one extra number

Der Rest ist dann nur noch „Eye Candy“.