Da die Lösung für Aufgabe 4 die Lösungen der anderen Aufgaben komplett enthält, will ich Ihnen hier nur diese eine darstellen:

Erstellen der zusätzlichen Buttons

Zunächst erstellen Sie bitte im Storyboard drei weitere Buttons, indem Sie sie nacheinander von der Object Library in die View ziehen.

Sie können die Buttons beliebig positionieren, es müssen aber ausreichend Constraints vorhanden sein, damit jeder Button eine eindeutige Position bekommt – auch dann noch, wenn der Benutzer anfängt, die Fenstergröße zu verändern.

Ich habe einen Button in die linke untere Ecke (Abstandskreuz links: 20 und unten: 20), einen in die rechte untere Ecke (Abstandskreuz rechts: 20 und unten: 20) und den letzten etwas über dem ursprünglichen Button platziert (Abstandskreuz unten: 20 und Horizontal Center in Container).

Nun benennen Sie die Buttons bitte entsprechend der Aufgabe um, indem Sie doppelt darauf klicken.

Vervierfachen der Actionmethode

Kopieren sie nun innerhalb von ViewController.swift die Actionmethode neuWürfelnButtonClicked() und fügen Sie sie dreimal darunter ein (Copy & Paste), so dass Sie vier Versionen dieser Methode haben. Dann benennen Sie die drei neuen Methoden so um, dass Sie den neuen Buttons entsprechen.

Wie Sie sie benennen, bleibt Ihnen überlassen, ich habe sie zwölferWürfelButtonClicked(), doubleWürfelButtonClicked() und dopplerWürfelButtonClicked() genannt.

Zudem habe ich, der Ordnung halber, die ursprüngliche Methode neuWürfelnButtonClicked() in sechserWürfelButtonClicked() umbenannt.

Verbinden Sie dann bitte die Buttons mit den Actionmethoden, indem Sie den Assistant editor verwenden (links der Code, rechts das Storyboard). Wenn Sie die ursprüngliche Methode wie ich umbenannt haben, müssen Sie sie erneut verbinden (die alte Verbindung wird dadurch automatisch gelöscht).

6er Würfel Actionmethode

Hier habe ich nichts grundlegendes verändert, denn es hat ja bereits funktioniert. Lediglich im Ausgabetext habe ich den Teilstring „Würfelergebnis:“ zu „Würfelergebnis (6er):“ erweitert.

12er Würfel Actionmethode

Die Funktionsaufruf arc4random_uniform(6) aus dem 6er Würfel erzeugt eine Zufallszahl zwischen 0 und 5. Durch ein nachgestelltes + 1 wird daraus eine Zahl zwischen 1 und 6. Analog erzeugt der Aufruf arc4random_uniform(12) eine Zahl zwischen 0 und 11, und auch hier sorgt ein + 1 dafür, dass daraus eine Zahl zwischen 1 und 12 wird, unser 12er Würfel. Der Code:

@IBAction func zwölferWürfelButtonClicked(sender: NSButton) {

  // Berechnen einer Zufallszahl zwischen 1 und 12

  let wurfErgebnis = arc4random_uniform(12) + 1

  // Erstellen des Ausgabestrings

  let wurfErgebnisText = "Würfelergebnis (12er): \(wurfErgebnis)"

  // Ausgabe

  resultLabel.stringValue = wurfErgebnisText

}

Doppler Würfel Actionmethode

Jetzt wird es schon etwas schwieriger. Der Dopplerwürfel zeigt die Zahlen 2, 4, 8, 16, 32, 64, die nachfolgende Zahl verdoppelt die vorhergehende.

Um Zahlen zu verdoppeln, nimmt man sie mal 2, also ist

2 = 2,
4 = 2 x 2,
8 = 2 x 2 x 2 usw.

Das kann man auch so formulieren, dass es sich bei allen Zahlen des Dopplerwürfels um Potenzen von 2 handelt (in der Programmierung trifft man sehr häufig darauf):

2 = 21, 4 = 22, 8 = 23, 16 = 24, 32 = 25, 64 = 26.

Wenn Sie nun eine Zufallszahl x erzeugen, die wie ein normaler Würfel zwischen 1 und 6 liegt, dann können Sie danach 2x berechnen und erhalten die Augenzahlen des Dopplerwürfels. Das ist unser Lösungsansatz. Nun muss der noch programmiert werden.

Die Berechnung einer Zufallszahl x zwischen 1 und 6 entspricht unserem normalen Würfelwurf, ist also keine große Herausforderung.

Um dann 2x zu berechnen, verwenden Sie die im Tipp benannte C-Funktion: ergebnis = pow(2, x)

Mathematisch ist das korrekt, nur leider erwartet pow() zwei Double als Eingabe und gibt auch Double zurück. Unser x ist aufgrund seiner Entstehung aber vom Typ UInt32 und als Rückgabewert wäre ein Integer (oder ein UInt32, wenn Sie die selbe Variable mehrfach verwenden wollen) ebenfalls die bessere Wahl.

Die Lösung ist im Tipp bereits skizziert: Double(x) verwandelt (castet) x in einen Double und UInt32(ergebnis) castet ergebnis zurück nach UInt32.

Das Ergebnis sehen Sie in folgendem Code:

@IBAction func dopplerWürfelButtonClicked(sender: NSButton) {

  // Berechnen einer Zufallszahl zwischen 1 und 6

  var wurfErgebnis = arc4random_uniform(6) + 1

  // Berechne 2 hoch wurfErgebnis

  wurfErgebnis = UInt32(pow(2, Double(wurfErgebnis)))

  // Erstellen des Ausgabestrings

  let wurfErgebnisText = "Würfelergebnis (Doppler): \(wurfErgebnis)"

  // Ausgabe

  resultLabel.stringValue = wurfErgebnisText

}

Double-Würfel Actionmethode

Weniger schwierig ist der Double-Würfel, er hat jedoch einen Kniff.

Wie bei der Besprechung der Zufallszahlen beschrieben, erzeugen Sie eine Double Zufallszahl aus dem Intervall [0, 1) durch den simplen Aufruf der Funktion drand48(). Aber wie verfahren Sie mit den Seed?

Setzen Sie den Aufruf srand48(time(nil)) direkt vor drand48(), so dass bei jedem Buttonklick der Seed erneut gesetzt wird, scheint erst einmal alles in Ordnung zu sein. Sie würfeln, bekommen ordnungsgemäß eine zufällige Zahl, würfeln dann erneut, bekommen eine andere zufällige Zahl, so soll es sein.

Der Seed verwendet aber den Funktionsaufruf time(nil), welcher die Anzahl der Sekunden seit dem 1. Januar 1970 zurückgibt. Die Anzahl der Sekunden ändert sich aber nur jede Sekunde einmal.

Das führt dazu, dass Sie den Button „Double Würfel“ nicht häufiger als einmal pro Sekunde betätigen dürfen. Tun Sie es doch, klicken Sie unablässig und mehrmals pro Sekunde auf diesen Button, dann ändert sich der Wert nur sekündlich, da innerhalb dieser Sekunde der Seed identisch ist. Probieren Sie das bitte einmal aus, programmieren Sie es absichtlich falsch, um den Effekt zu sehen.

Der Seed funktioniert nämlich so, dass Sie ihn einmal setzen und dann bei jedem erneuten Aufruf von drand48() eine neue Zufallszahl erhalten, eine erste, zweite, dritte usw., alle sehr zufällig und voneinander verschieden. Setzen Sie dann den Seed erneut auf denselben Wert wie das erste Mal, erhalten Sie wieder genau die selbe Folge von Zufallszahlen wie beim ersten Mal. Der Zeitraum zwischen den Aufrufen von drand48() spielt dabei keine Rolle.

Spielen Sie damit einmal herum, setzen Sie im nachfolgenden, korrekten Code, den Seed statt auf srand48(time(nil)) einfach mal auf srand48(12345). Bei ersten Programmstart ist alles wunderbar, aber beim zweiten Programmstart sehen Sie, dass sich die scheinbar zufällige Zahlenfolge identisch wiederholt. Berechnete Zufallszahlen sind eben Pseudozufallszahlen.

Kurz und gut, setzen Sie bitte den Seed in der Methode viewDidLoad(), damit er nur einmal zum Start der Programms aufgerufen wird. Der Code für die beiden Methoden:

override func viewDidLoad() {

  super.viewDidLoad()

  resultLabel.stringValue = "Bitte würfeln Sie."

  srand48(time(nil))

}

@IBAction func doubleWürfelButtonClicked(sender: NSButton) {

  // Berechnen einer Zufallszahl aus dem Intervall [0, 1)

  let wurfErgebnis = drand48()

  // Erstellen des Ausgabestrings

  let wurfErgebnisText = "Würfelergebnis (double): \(wurfErgebnis)"

  // Ausgabe

  resultLabel.stringValue = wurfErgebnisText

}

Beitragsbild: Ricky Jay dice in exhibit von Susan Gerbic in abgewandelter Form (CC BY SA 3.0)

Projekt Zufall 13: Lösungen

Ein Gedanke zu „Projekt Zufall 13: Lösungen

  • 9. April 2015 um 20:18
    Permalink

    die beiden Buttons links unten und rechts unten in der Ecke verhalten sich bei mir eigenartig: Wenn ich das Programmfenster größerziehe, werden diese Buttons breiter
    Als Constraints habe ich:
    Align Center X to: Superview – Equals: 190,
    Leading Space to: Superview – Equals 20
    Bottom Space to: Superview – Equals 20
    Ich hab’s mit einem Width-Constraint versucht – daraufhin liess sich das Programmfenster nicht mehr breiter ziehen.

    Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.