Kapitel 3.3.4: Der unäre Minus- und Plus-Operator

Kapitel 3: Einfache Operatoren / 3.3 Arithmetische Operatoren / 3.3.4 Der unäre Minus- und Plus-Operator

Der unäre Minus-Operator (-a) wechselt das Vorzeichen des Operanden. Das Ergebnis wird zurückgegeben, der Wert der Variablen selbst aber nicht verändert.

Ist a eine positive Zahl, dann ist -a die negative Zahl mit dem selben Betrag wie a (zur Erinnerung: der Betrag streicht das Vorzeichen einer Zahl weg). Ist a eine negative Zahl, dann ist -a die positive Zahl mit dem selben Betrag.

Spätestens am Beispiel wird es sofort klar: Ist a = 3, dann ist -a gleich -3. Und ist a = -3, dann ist -a gleich 3. Mehr steckt nicht dahinter.

Bitte versuchen Sie nun einmal, die Werte der Variablen a bis d aus folgendem Code zu schließen:

var a = 5
var b = -a
var c = --a
var d = -(-a)

Ich hab’ Sie hier ein bisschen hereingelegt, aber von vorne:

Zunächst wird der Variablen a der Wert 5 zugewiesen, also a = 5. In der zweiten Zeile gibt -a den Wert -5 zurück, also ist b = -5.

In der dritten Zeile wird es komplizierter: Wird das Vorzeichen von a doppelt gewechselt, dann hat a wieder sein urspründliches Vorzeichen. a ist 5, also gibt --a den Wert 5 zurück und c = 5, ist das so korrekt?

Leider nein, denn --a ist der Dekrement-Operator. Hier wird zunächst a und eins verringert und das Ergebnis zurückgegeben, es gilt also: c = 4 (und a jetzt übrigens auch).

In der vierten Zeile geschieht nun das, was in der dritten vermeintlich geschah: -(-a) ist der doppelte Vorzeichenwechsel. Da a inzwischen 4 ist, ist nun auch d = 4.

Das unäre Minus kann auf Integer- und Gleitkommazahlen angewendet werden, bei Boolean und Tupeln funktioniert es aber nicht.

Das unäre Plus (+a) wird syntaktisch (bezüglich der Zeichensetzung) genauso verwendet wie das unäre Minus und es gelten auch die gleichen Einschränkungen bezüglich der zu verwendenden Typen.

Anders als das Minus, rechnet das Plus aber nicht, sondern gibt lediglich den Wert seines Operanden zurück.

Folglich wird es nur aus optischen Gründen verwendet, etwa wenn einer Liste negativer Zahlen eine Liste positiver Zahlen gegenübersteht und der Programmierer möchte, dass alles schön symmetrisch aussieht.

Man braucht das unäre Plus also nicht wirklich, aber weil es auch in vielen anderen Programmiersprachen vorhanden ist und nicht weiter stört.. Warum also nicht.

Kapitel 3.3.3: Inkrement- und Dekrement-Operatoren

Kapitel 3: Einfache Operatoren / 3.3 Arithmetische Operatoren / 3.3.3 Inkrement- und Dekrement-Operatoren

Wie viele andere Sprachen auch, verfügt Swift über zwei Inkrement– (a++ und ++a) und zwei Dekrement-Operatoren (a-- und --a).

Diese vier Operatoren sind auf alle Zahlentypen anwendbar. Dabei erhöhen die beiden Inkrement-Operatoren den Wert der verwendeten Variable um 1, während die beiden Dekrement-Operatoren ihn um 1 verringern.

a++ und ++a sind also eine Kurzschreibweise für a = a + 1, so wie a-- bzw. --a eine Kurzschreibweise für a = a – 1 sind.

Ob die beiden Operatorzeichen nun vor dem Operanden stehen (Präfixoperator) oder dahinter (Postfixoperator) hat keinen Einfluss darauf, wie der Operand verändert wird: Bei zwei Pluszeichen wird er immer um eins erhöht, bei zwei Minuszeichen immer um eins verringert.

Die vier Operatoren haben aber auch einen Rückgabewert: Werden die beiden Operatorzeichen als Präfix verwendet (++a bzw. --a), dann wird zuerst der Variablenwert erhöht bzw. abgesenkt, erst dann wird der Variablenwert zurückgegeben. Werden sie als Postfix verwendet (a++ bzw. a--), dann ist es umgekehrt: Es wird zuerst der Variablenwert zurückgegeben und erst dann wird der Variablenwert verändert.

Ein Beispiel:

var a = 13      // a wird auf 13 gesetzt
var b = a++     // b wird auf 13 gesetzt und dann a auf 14 erhöht
var c = --b     // b wird auf 12 verringert, dann c auf 12 gesetzt

Wenn Sie den Rückgabewert nicht benötigen, lassen Sie ihn einfach ins Leere laufen und verwenden Sie nur die wertverändernde Eigenschaft, z.B. in dem Sie a++ ohne eine Zuweisung als einzigen Befehl in einer Zeile verwenden.

Apple empfiehlt, das Postfix nur dann zu verwenden, wenn man es explizit braucht. Wenn es egal ist, solle man das Präfix verwenden, da dessen Verhalten (der verminderte oder erhöhte Wert wird zurückgegeben) eher den Erwartungen eines Programmierers entspräche.

Meine Erfahrungen sagen etwas anderes: Die meisten Programmierer verwenden a++ viel häufiger als die anderen drei Operatoren, danach kommt a--. Die beiden Präfix-Varianten folgen mit einer weit geringeren Häufigkeit und werden von den meisten nur dann genutzt, wenn sie explizit benötigt werden, also genau entgegengesetzt zu Apples Empfehlung.

Das liegt wahrscheinlich daran, dass der Name der Computersprache C++ vielen Programmierern so geläufig ist, dass sie ihn im Programmcode unbewusst oder absichtlich zitieren.

Ein kleiner Exkurs: C++ wurde von Bjarne Stroustrup erfunden und der nannte die neue Sprache zunächst „C mit Klassen“, denn C++ war eben C erweitert um Klassen. Sein Mitarbeiter Rick Mascitti kam dann auf die Idee, die Sprache C++ zu nennen: Die Sprache C erhöht um 1, Eins mehr als C, Nachfolger von C. Das verfing und geht also tatsächlich auf das Inkrement-Postfix zurück.

Detailverliebte und C++ wohlmeinende Leute haben später betont, dass die Verwendung des Postfix suggerieren würde, dass die Neuerungen nicht verwendet werden könnten, da sie erst nach der Benutzung hinzukämen. Richtiger, so sagten sie, wäre die Bezeichnung ++C. Es antworteten ihnen Leute, die C++ nicht so wohlmeinend gegenüberstanden: Nein, nein, sagten diese, die Bezeichnung sei absolut korrekt, aus genau den Gründen.

Beitragsbild: Martinet noir Apus apus Common Swift von Sébastien Bertru in abgewandelter Form (CC BY-SA 2.0)

Kapitel 3.3.2: Der Rest-Operator

Kapitel 3: Einfache Operatoren / 3.3 Arithmetische Operatoren / 3.3.2 Der Rest-Operator

Der Rest-Operator (a % b, engl.: Remainder Operator) führt eine Division mit Rest aus und gibt diesen Rest dann zurück. Das funktioniert im wesentlichen wie früher in der Grundschule: Es wird geprüft, wie oft b in a hineinpasst, und dann wird zurückgegeben, wieviel von a zum Schluss noch übrigbleibt.

Nehmen wir 13 % 5 als Beispiel. Die 5 passt zwei mal in die 13, zwei mal 5 ist 10, der Rest beträgt 3. Also 13 = 5 • 2 + 3 und damit ist 13 % 5 = 3.

Die Aufteilung von 13 durch die Gleichung 13 = 5 • 2 + 3 lässt sich auch allgemein schreiben:

a = b • Faktor + Rest

wobei Faktor die betragsmäßig größte ganze Zahl darstellt, die diese Gleichung so lösen kann, dass a und Rest dasselbe Vorzeichen haben. Hierbei stellt Rest das Ergebnis der Rest-Operation dar.

Diese allgemeine Beschreibung ist nötig, um den Rest Operator nicht nur auf ganze Zahlen größer Null anwenden zu können, sondern auch auf negative und Fließkommazahlen.

Kurz zur Erklärung von betragsmäßig größte Zahl: Der Betrag einer Zahl streicht ein negatives Vorzeichen weg, wenn es vorhanden ist: Der Betrag von 5 ist 5 und der Betrag von -5 ist auch 5. Durch diesen „Trick“ ist -3 betragsmäßig größer als -2, obwohl -3 als Zahl natürlich kleiner ist als -2.

Zur Berechnung des Rests von negativen Zahlen verwendet Swift also dieselbe allgemeine Formel, angenommen bei a % b ist a negativ:

-13 % 5 = -3  da eingesetzt in die Gleichung gilt: -13 = 5 • (-2) + (-3)

Was passiert, wenn bei a % b nun b negativ ist? Antwort: Es hat keinen Einfluss auf das Ergebnis. Wenn Sie an mathematischen Knobeleien interessiert sind, können Sie sich jetzt kurz überlegen, warum das so ist. Für alle anderen erkläre ich es jetzt:

Wenn b negativ ist, dann ändert sich in der Gleichung nur das Vorzeichen des Faktors, alles andere bleibt gleich, insbesondere bleibt auch der Rest, das Ergebnis des Rest-Operators gleich:

-13 % -5 = -3  da eingesetzt in die Gleichung gilt: -13 = (-5) • 2 + (-3)

In anderen (Programmier-)Sprachen heißt der Rest-Operator oft Modulo-Operator und wird ebenfalls durch das Prozent-Zeichen % dargestellt. Apple hat seinen %-Operator aber bewusst nicht so genannt, um das besondere Verhalten bei negativen Zahlen herauszustreichen. Dieses sei in Swift eher die Berechnung eines Rests als die eines Modulo.

Ob dem tatsächlich so ist, ist Geschmachssache. Tatsächlich stimmen praktisch alle Implementierungen des %-Operators miteinander überein, wenn es um die Berechnung positiver Zahlen geht. Werden die Zahlen negativ, beginnen die Programmiersprachen sich zu unterscheiden. Mathematisch korrekt sind hierbei die wenigsten, auch Swifts Implementierung entspricht nicht der mathematischen Konvention, die auch das Vorzeichen des zweiten Operanden mit in das Ergebnis einbezieht. Ob Apples Anzatz dafür nun intuitiv korrekt ist, müssen Sie selbst beurteilen.

Zur vollständigen Beschreibung fehlt nun noch die Berechnung von Fließkommazahlen, aber auch hier ändert sich an der dargestellten Gleichung nichts:

5,6 % 0,5 = 0,1 da eingesetzt in die Gleichung gilt: 5,6 = 0,5 • 11 + 0,1

Betrachten wir einige Sonderfälle: Was passiert, wenn bei a % b nun b größer ist als a? Nichts besonderes, der Faktor ist Null und die Gleichung wird wie bisher aufgelöst:

1 % 5 = 1 da eingesetzt in die Gleichung gilt: 1 = 5 • 0 + 1

Und wenn nun a oder b gleich Null sind? Wenn a gleich Null ist, wird gerechnet wie bisher:

0 % 5 = 0 da eingesetzt in die Gleichung gilt: 0 = 5 • 0 + 0

Ist aber b gleich Null, kommt es zu einer klassischen Runtime Exception: Division by zero, das Teilen durch Null ist mathematisch nicht erlaubt, das gilt für den Rest-Operator genauso wie für den Divisions-Operator (a / b).

Wenn man nicht gerade Zahlentheoretiker ist, beschränkt sich die mathematische Bedeutung des Rechnens mit Rest mehr oder weniger auf die bereits zu Anfang erwähnten Erfahrungen in der Grundschule und dient vor allem dazu, die Kinder auf das „richtige“ Dividieren mit Kommazahlen vorzubereiten.

In der Programmierung liegt die Sache anders: Des Rest-Operator ist eine sehr große Hilfe beim Aufteilen eines kontinuierlichen Zählers in Segmente. Und ich lehne mich mal aus dem Fenster und behaupte 90% aller Verwendungen des %-Operators dienen genau diesem Zweck.

Wenn eine Schleife von 1 bis 100 durchläuft und man jedes dritte Mal etwas tun möchte, prüft man ob die Schleifenvariable % 3 gleich Null ist. Dies und Varianten davon machen die Bedeutung des Rest-Operators aus.

Beitragsbild: Martinet noir Apus apus Common Swift von Sébastien Bertru in abgewandelter Form (CC BY-SA 2.0)

Kapitel 3.3.1: Grundrechenarten

Kapitel 3: Einfache Operatoren / 3.3 Arithmetische Operatoren / 3.3.1 Grundrechenarten

Die arithmetischen Operatoren der vier Grundrechenarten Addition (+), Subtraktion (-), Multiplikation (*) und Division (/) werden in Swift für alle Zahlentypen unterstützt.

1 + 1 // Ergibt 2
10 - 11 // Ergibt -1
3.0 * 1.5 // Ergibt 4.5
4.5 / 1.5 // Ergibt 3.0

Der Rückgabewert ist das Ergebnis der Berechnung. Beide Operanden müssen vom selben Typ sein, woraus sich dann auch der Typ des Rückgabewerts ergibt. Möchten Sie z.B. einen Integer mit einem Double multiplizieren, dann müssen Sie zuvor einen der beiden Typen konvertieren:

var a: Int = 3
var b: Double = 5.0
var c: Double = 0.0

c = Double(a) * b

Wenn bei einer Rechenoperation das Ergebnis den zulässigen Wertebereich des verwendeten Typs sprengt, dann kommt es zu einer Runtime Exception – wie z.B. im folgenden Fall, da Int8 einen Maximalwert von 127 hat:

var a: Int8 = 127
var b: Int8 = 1

var c: Int8 = a + b

Andere Sprachen sind da gelassener. Wenn der zulässige Wertebereich verletzt wird, kommt es dort zu einem sogenannten Überlauf (engl.: overflow), es wird praktisch auf der gegenüberliegenden Seite des Wertebereichs weitergezählt. Die Variable c hätte im Falle eines Überlaufs den Wert -128 angenommen.

Da dieses overflow-Verhalten von Programmierern aber oft nicht bedacht wird und das Programm in einem solchen Fall dann mit völlig falschen Werten weiterrechnet, gibt es in Swift zunächt einmal keinen Überlauf. Setzen Sie aber ein Kaufmannsund (&) vor den Operator, dann schalten Sie das overflow-Verhalten wieder ein, dazu später noch mehr.

Da die vier Grundrechenarten alle einen Rückgabewert haben, lassen sie sich – anders als der Zuweisungsoperator – miteinander verketten. Hierbei wird aber nicht der gesamte Term stur von rechts nach links ausgerechnet, sondern es gelten Rechenregeln wie etwa „Punktrechnung vor Strichrechnung“. Klammern können ebenfalls verwendet werden. Auch zu dieser sogenannten Operatorrangfolge komme ich später noch einmal zurück, wenn Sie mehr Operatoren kennengelernt haben.

Der Plus-Operator kann außer zur Addition von Zahlen, auch zur Konkatenation von Strings, also dem aneinanderhängen von Strings verwendet werden:

"Hallo" + " " + "Welt" // Ergibt "Hallo Welt"

Beitragsbild: Martinet noir Apus apus Common Swift von Sébastien Bertru in abgewandelter Form (CC BY-SA 2.0)

Kapitel 3.2: Der Zuweisungsoperator

Kapitel 3: Einfache Operatoren / 3.1 Operatoren in Swift

Der Zuweisungsoperator (a = b) initialisiert oder aktualisiert den Wert von a auf den Wert von b.

Dieser Operator ist Ihnen sicher schon gut bekannt, da mit Hilfe dieses Operators Variablen und Konstanten deklariert und im Wert verändert werden können:

var a = 100
let b = 200
a = b
// a hat jetzt den Wert 200

Nicht viel neues also, nur eben jetzt aus der Perspektive des Operators. Sie wissen auch bereits, dass anstelle eines Einzelwertes auch ein Tupel zugewiesen werden kann:

let (a, b) = (1, 2)
// a hat jetzt den Wert 1 und b den Wert 2

Eine Besonderheit des Zuweisungsoperators in Swift ist, dass er keinen Rückgabewert hat.

Warum sollte der Zuweisungsoperator einen Rückgabewert haben, fragen Sie sich jetzt vielleicht. Apple hat sich diese Frage auch gestellt, keine zufriedenstellende Antwort gefunden und den Rückgabewert weggelassen.

Andere Sprachen machen das anders. So gibt zum Beispiel die Sprache C, die für die Swift Operatoren immerhin Pate gestanden hat, bei einer Zuweisung den Wert der Zuweisung zurück. Dies hat den Vorteil, dass so Zuweisungsketten (a = b = c) möglich werden:

In C wird so eine Zuweisungskette von rechts ausgeführt, d.h. zuerst bekommt b den Wert von c zugewiesen. Der Rückgabewert ist der Wert von c. Dann wird a dieser Rückgabewert zugewiesen. Am Ende haben a, b und c alle den Wert, den ursprünglich c hatte.

In Swift sind solche Zuweisungsketten also nicht möglich. Das ist aber nicht der schlechten Lobby von Zuweisungsketten geschuldet, sondern ein Seiteneffekt. Denn viel wichtiger ist, dass folgende Konstruktion nicht mehr funktioniert:

if (a = b) {
  // dies führt in Swift zu einem Compilefehler
}

Nehmen Sie einmal an, a und b wären Booleans. b wäre true und a wäre false. Dann würde bei dieser Zuweisung a den Wert von b bekommen, es wären also a und b true, und nehmen Sie weiter an, der Rückgabewert dieser Zuweisung wäre true. Das if prüft nun, ob der nachfolgende Ausdruck true oder false ist. Da er true zurückliefert, also true ist, wird der Code in den geschweiften Klammern ausgeführt.

Schaut man sich den Code aber an, hatte der Programmierer wahrscheinlich etwas ganz anderes im Sinn: Vermutlich wollte er die Variablen a und b auf Gleichheit prüfen und bei Gleichheit den Code in den gescheiften Klammern ausführen. Nicht nur dass bei unserer Annahme a und b nicht gleich sind und dennoch der optionale Code ausgeführt wird, zudem findet noch eine unbeabsichtigte Zuweisung statt.

Der Programmierer hätte statt = den Vergleichsoperator == verwenden müssen, um auf Gleichheit zu prüfen. Um diesen wirklich sehr häufigen Programmierfehler zu unterbinden, darum also, hat Apple auf einen Rückgabewert von Zuweisungen verzichtet. Gute Entscheidung.

Beitragsbild: Martinet noir Apus apus Common Swift von Sébastien Bertru in abgewandelter Form (CC BY-SA 2.0)

Kapitel 3.1: Operatoren in Swift

Kapitel 3: Einfache Operatoren / 3.1 Operatoren in Swift

Operatoren sind spezielle Zeichen, die vor, hinter oder zwischen Werte gesetzt werden, um diese miteinander zu vergleichen, sie zu kombinieren oder auf andere Weise zu verändern.

Beispielsweise ist das Pluszeichen ein Operator, der zwei Zahlen addieren kann:

var summe = 13 + 3

Ein weiteres Beispiel ist der Inkrementoperator, bestehend aus zwei Pluszeichen, der einen Zahlenwert um eins erhöht. Der folgende Code erhöht den Wert unserer summe um eins, also von 16 auf 17:

summe++

Als drittes Beispiel soll der im Vergleich kompliziert anmutende Bedingungsoperator dienen. Bestehend aus einem Fragezeichen und einem Doppelpunkt, verknüpft er eine Zuweisung mit einer Bedingung:

var ausgabe = (summe < 18) ? "kleine Zahl" : "große Zahl"

Die Bedingung ist in diesem Beispiel summe < 18 – wobei es sich bei dem Kleiner-als-Zeichen um einen Verleichsoperator handelt. Trifft die Bedingung zu, ist summe also tatsächlich kleiner als 18, dann wird die Variable ausgabe auf den Wert „kleine Zahl“ gesetzt. Ansonsten wird sie auf den Wert „große Zahl“ gesetzt. Die Klammern um den Vergleich herum sind übrigens nicht nötig, ich habe sie nur der besseren Lesbarkeit halber hinzugefügt.

Um Operatoren grob zu klassifizieren, unterteilt man sie in unäre, binäre und ternäre Operatoren:

Unäre Operatoren haben einen Operanden, also einen Wert, auf den der Operator angewendet wird. Beispiele sind der Inkrementoperator (a++) oder das unäre Minus (-a), das den negativen Wert einer Zahl zurückliefert. Ein unärer Operator steht entweder vor dem Operanden, dann nennt man ihn einen unäreren Präfixoperator, oder er steht hinter dem Operanden, dann heißt er unärer Postfixoperator. Diese Begriffe werden deutlich später noch einmal wichtig, wenn es darum geht, eigene Operatoren zu schreiben. Jetzt geht es vor allem darum, sie schon einmal gehört zu haben.

Binäre Operatoren haben zwei Operanden, so wie bei (a + b) oder (a < b). Die Tatsache, dass binäre Operatoren immer zwischen ihren beiden Operanden stehen, nennt man Infixnotation, es handelt sich also um Infixoperatoren.

Ternäre Operatoren, also solche mit drei Operanden, gibt es in Swift (und in so ziemlich allen anderen Sprachen auch) nur einen, nämlich den bereits beschriebenen Bedingungsoperator.

Die Operatoren in Swift sind im wesentlichen denen von C nachempfunden, finden sich aber so oder so ähnlich auch in vielen anderen Programmiersprachen wieder. In einigen Fällen wurde Swift allerdings gegen typische Programmierfehler abgesichert, wodurch sich die Benutzung im Detail etwas unterscheidet. Ich werde auf diese Besonderheiten eingehen, wenn ich im Folgenden die einzelnen Operatoren beschreibe.

Beitragsbild: Martinet noir Apus apus Common Swift von Sébastien Bertru in abgewandelter Form (CC BY-SA 2.0)

Projekt Zufall 13: Lösungen

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 12: Aufgaben

Aufgabe 1: Ein Würfel mit 12 Seiten
Schwierigkeit: einfach

Bei einigen Spielen gibt es Würfel, die mehr als 6 Seiten haben. Bitte ändern Sie das Programm so ab, dass Sie statt mit einem 6-seitigen nun mit einem 12-seitigen Würfel würfeln.

Tipp: Verändern Sie die Berechnung der Zufallszahl so, dass nicht mehr eine zufällige Zahl zwischen 1 und 6 herauskommt, sondern eine zwischen 1 und 12.

Aufgabe 2: Ein Double-Würfel
Schwierigkeit: mittel

Bei der Besprechung der Zufallszahlen haben Sie gesehen, wie Sie eine Zufallszahl zwischen 0 und 1 erstellen. Bitte bauen Sie das Programm so um, dass Sie fortan Zufallszahlen von Typ Double aus dem Intervall [0, 1) „würfeln“.

Tipp: Vergessen Sie nicht den Seed und denken Sie daran, dass dieser während des gesamten Programmablaufs nur einmal aufgerufen werden darf und nicht bei jedem Würfelwurf erneut. Wo wäre dafür die geeignete Stelle im Code?

Aufgabe 3: Ein Backgammon Dopplerwürfel
Schwierigkeit: schwer

Bei dem Spiel Backgammon gibt es einen sogenannten Dopplerwürfel, das ist ein 6-seitiger Würfel, der mit den Zahlen 2, 4, 8, 16, 32 und 64 beschriftet ist. Zwar wird beim Backgammon damit nicht gewürfelt, aber wir können das ja trotzdem tun:

Bitte ändern Sie das Programm so ab, dass Sie von nun an mit einem Dopplerwürfel würfeln.

Tipp 1: Wenn Sie unter Swift xy (x hoch y) berechnen wollen, also zum Beispiel 33 = 27, dann verwenden Sie dafür bitte die Funktion pow(x, y). Dies ist übrigens auch eine alte C-Funktion. Aber Achtung: Sowohl die beiden Parameter von pow(.., ..) sind von Typ Double, wie auch der Rückgabewert dieser Funktion.

Tipp 2: Um den Variablentyp eines Wertes zu verändern, verwenden Sie den Zieltyp als Funktion und übergeben dieser die Variable, die Ihren Wert enthält. So gibt beispielsweise die Funktion Double(variable) den Wert von variable als Double zurück, auch wenn variable etwa vom Typ Integer ist.

Tipp 3: Alternativ können Sie natürlich auch if und else verwenden.

Aufgabe 4: Alleswürfler
Schwierigkeit: schwer

Fügen Sie dem Programmfenster drei weiter Buttons hinzu und beschriften Sie die nun insgesamt vier Buttons mit den Texten „6er Würfel“, „12er Würfel“, „Double Würfel“ und „Dopplerwürfel“. Verändern Sie das Programm außerdem so, dass je nachdem, welcher Button vom Benutzer verwendet wird, ein entsprechender Wert in der Textausgabe erscheint.

Viel Spaß und viel Erfolg! Und falls Sie partout nicht weiterkommen: Die Lösungen erscheinen nächste Woche.

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

Projekt Zufall 11: Hausputz

Zur Fertigstellung der Applikation fehlen nur noch ein paar Feinheiten, einmal noch wirbeln wir dafür durch das Programm.

Das Menü enthält beispielsweise noch viele Punkte, die wir nicht benötigen: Der Menüpunkt „File“ macht keinen Sinn, da unsere Anwendung weder dokumentenbasiert ist, noch eine Möglichkeit zum Drucken anbietet. „Edit“ und „Font“ sind ohne Eingabefelder innerhalb der Applikation auch überflüssig, genau wie „View“ und „Help“ ohne entsprechende Funktionen. Der Punkt „Window“ kann so bleiben wie er ist, und aus dem Menü „Zufall“ werfen wir nur „Preferences..“ heraus, da wir auch die nicht haben.

Um das unzusetzen, öffnen Sie bitte das Storyboard. Ganz oben sehen Sie das Menü. Um einen Eintrag daraus zu löschen, markieren Sie ihn einfach und drücken Sie dann die Taste zum Rückwärtslöschen (Del, ←). Machen Sie das bitte bei allen erwähnten Menüpunkten und vergessen Sie beim Löschen der „Preferences..“ nicht den Separator darunter (Abbildung 11.1).

Abbildung 11.1: Löschen des Separators
Abbildung 11.1: Löschen des Separators

Wenn Sie währenddesssen die Document Outline links einblenden, können Sie gut sehen, ob Ihnen noch etwas entgangen ist.

Sind dann alle veränderten Dateien abgespeichert (gearbeitet haben wir nur an den Dateien ViewController.swift und Main.storyboard), können wir sie committen:

Sie erinnern sich, ganz zu Anfang haben wir beim Erstellen der Projektdatei ein Git Repository miterzeugt. Auch jetzt will ich nicht ins Detail gehen, doch soviel. Wenn wir eine Datei committen, dann zeichnen wir den aktuellen Stand dieser Datei bezüglich aller Zwischenstände aus. Zu diesem Stand können wir jederzeit zurückkehren, wir halten ihn fest.

Da unsere Applikation nun einen guten Stand hat, committen wir ihn also. Dazu rechts-klicken Sie im Project navigator bitte auf die Datei und wählen Source ControlCommit „Dateiname“ aus. Sie gelangen in eine Ansicht ähnlich dem Version editor, in der Sie auf der rechten Seite den zuletzt committeten Stand sehen und links den, den Sie jetzt committen wollen. Beim View Controller ist dieser Vergleich natürlich sprechender als bei der eher kryptischen Textversion des Storyboards.

Darunter befindet sich ein sehr großes Eingabefeld, beschriftet mit „Enter commit message here“, „Hier einen Kommentar für den Commit eintragen.“ Dieser Kommentar ist verpflichtend, geben Sie für beide Dateien hier zum Beispiel „Das Programm ist fertig.“ ein und klicken Sie anschließend rechts unten den Button „Commit 1 file“ um die Datei zu committen.

Das wars. Einige weitere Dinge, die auch noch zum Hausputz zählen, sparen wir uns für ein späteres Projekt auf, so zum Beispiel die Erstellung und Einbindung eines eigenen Icons, die Verbesserung des About Dialogs oder eine Lokalisierung (Übersetzung) der Applikation in verschiedene Sprachen.

Damit ist dieser Teil der Applikation und des Projekts „Zufall“ abgeschlossen, es folgen aber noch ein paar Aufgaben, die den Umfang der Applikation deutlich erweitern. Versuchen Sie sich daran und geben Sie nicht so schnell auf, falls Sie nicht weiterkommen. Am meisten lernen Sie durch’s Selbermachen. Erst wenn Sie die Aufgaben eigenständig programmiert haben oder während dessen tatsächlich nicht mehr weiterwissen – was nicht schlimm wäre, denn dass Sie sich mit den Aufgaben beschäftigen ist das wichtige – erst dann gehen Sie bitte zu der Lösungsbeschreibung über, um dieses Projekt rund für Sie abzuschließen.

Viel Spaß und viel Erfolg bei den Aufgaben.

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

Projekt Zufall 10: Nun wird gewürfelt

Um die Berechnung der Zufallszahlen in unser Projekt einzubauen, ändern wir die Funktion neuWürfelnButtonClicked() wie folgt:

@IBAction func neuWürfelnButtonClicked(sender: NSButton) {

  // Berechnen einer Zufallszahl zwischen 1 und 6

  let wurfErgebnis = arc4random_uniform(6) + 1

  // Erstellen des Ausgabestrings

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

  // Ausgabe

  resultLabel.stringValue = wurfErgebnisText

}

Die Berechnung der Zufallszahl und die Ausgabe haben wir bereits besprochen, erklärungswürdig ist lediglich die Erstellung des Ausgabestrings:

Verwenden Sie einen rückwärtsfallenden Schrägstrich (Backslash) innerhalb einer Stringdeklaration, gefolgt von einem Variablennamen in runden Klammern, wird der Inhalt dieser Variable automatisch in einen String umgewandelt und dieser anstelle der beschriebenen Syntax in den String eingefügt.

Da wir die Textausgabe „Die Applikation ist gestartet.“ nur zu Testzwecken verwendet hatten, ersetzen Sie sie in der Funktion viewDidLoad() bitte durch den String „Bitte würfeln Sie.“ Damit ist das Programm in seinem Funktionsumfang auch schon vollständig.

Speichern Sie die Datei bitte (cmd + s) und starten Sie die Applikation.

Abbildung 10.1: Es kann gewürfelt werden.
Abbildung 10.1: Es kann gewürfelt werden.

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