Java Videotraining Werbung

Videotraining Spring 3 Boot Werbung

1. Imperative Sprachkonzepte

Die virtuelle Maschine macht im Kern nichts anderes, als Ausdrücke auszuwerten und Anweisungen aufzuführen. Die Aufgaben dieses Kapitels stellen die unterschiedlichen Datentypen, diverse Operatoren und die bedingte Ausführung in den Mittelpunkt.

Voraussetzungen

  • einfache Bildschirmausgaben tätigen können

  • Benutzereingaben empfangen

  • Datentypen unterscheiden können

  • Variablen deklarieren können

  • Zuweisung und Operatoren kennen

  • Fallunterscheidung einsetzen können

  • Schleifen für Wiederholungen nutzen können

  • ineinandergeschachtelte Schleifen einsetzen können

  • Unterprogramme mit Methoden deklarieren und implementieren können

  • Unterschied zwischen Argument und Parameter kennen

  • überladene Methoden nutzen können

Verwendete Datentypen in diesem Kapitel:

1.1. Bildschirmausgaben

Im ersten Kapitel hat das Java-Programm eine einfache Ausgabe realisiert. Darauf wollen wir aufbauen und lernen, wie man Sonderzeichen schreibt (etwa Anführungszeichen), Zeilenumbrüche setzt oder einfache formatierte Ausgaben erreicht.

1.1.1. SVG-Spezifikation kennenlernen ⭐

Grafische Darstellungen laden zum Spielen ein, weshalb unsere Java-Programme etwas zeichnen sollen. Die Java SE enthält eine Bibliothek, mit der man ein Fenster öffnen und Inhalt zeichnen kann, doch ist das nicht mit ein paar Codezeilen erledigt. Daher wollen wir einen anderen Weg gehen, und zwar über SVG. Die Abkürzung steht für Scalable Vector Graphics, ein Standard für Vektorgrafiken. SVG erlaubt die Beschreibung zweidimensionaler Vektorgrafiken in Text, und Text kann ein Java-Programm leicht schreiben.

Aufgabe:

1.1.2. Einen SVG-Kreis auf die Konsole schreiben ⭐

Für Bildschirmausgaben gibt es in Java mehrere Möglichkeiten. Im Regelfall kommt die Methode print(…​), println(…​) oder printf(…​) zum Einsatz. Diese Methoden befinden sich am System.out-Objekt. Neben System.out gibt es System.err, aber das ist für Fehlerausgaben reserviert. Einige Entwickler verwenden auch das Console-Objekt zur Ausgabe, wir bleiben bei System.out.print*(…​).

Captain CiaoCiao benötigt für Schießübungen einen gefüllten Kreis, der später ausgedruckt werden kann. Dazu wollen wir ein neues Java-Programm entwickeln.

Zur Bildschirmausgabe lassen sich nutzen:

System.out.print( "Text ohne anschließenden Zeilenumbruch" );
System.out.println( "Text mit anschließendem Zeilenumbruch" );
System.out.printf( "Text mit anschließendem Zeilenumbruch%n" );
Write an SVG circle on the console

Aufgabe:

  • Lege eine neue Klasse SvgCircle1 an.

  • Lege ein main(…​)-Methode an, damit wir das Programm später starten können.

  • Nutze in der main(…​) die bekannten print*(…​)-Methoden, um folgenden Text auf die Konsole zu bringen:

    <svg height='400' width='1000'><circle cx='100' cy='100' r='50' /></svg>
  • Trage die Konsolenausgabe auf die Webseite https://tutego.de/go/trysvgcircle ein, und nach dem Klicken von Run » wird ein Kreis zu sehen sein. Wir wollen im Folgenden immer wieder auf die Webseite zurückkommen, wenn SVG-Elemente angezeigt werden sollen.

    W3schools svg editor circle
    Abbildung 1. Anzeige einer SVG-Ausgabe
  • Ändere das Programm so, dass Zeilenumbrüche in der Ausgabe vorkommen. Das Ziel soll sein:

    <svg height='400' width='1000'>
      <circle cx='100' cy='100' r='50' />
    </svg>
  • Ändere erneut das Programm so ab, dass statt einfacher nun doppelte Anführungszeichen im String sind. Das Ziel soll sein:

    <svg height="400" width="1000">
     <circle cx="100" cy="100" r="50" />
    </svg>

1.2. Variablen und Datentypen

Variablen speichern Informationen, und Variablen haben in Java immer einen Typ. Der Compiler weiß zu jeder Zeit, welchen Typ eine Variable hat, und auch, welchen Typ ein Ausdruck hat.

Java hat acht eingebaute Datentypen: boolean, byte, char, short, int, long, float und double. Man kann in ihnen numerische Werte und Wahrheitswerte speichern. Die Wahrheitswerte können mit true und false belegt werden. Bei den numerischen Werten haben wir drei verschiedene Gruppen:

  • Wir haben numerische Werte für Unicode-Zeichen und nutzen dafür den Datentyp char. Dazu kommen Datentypen für allgemeine Ganzzahlen und Fließkommazahlen.

  • Ganzzahlen haben grundsätzlich Vorzeichen. Wir haben davon vier verschiedene Typen: byte, short, int und long. Die Typen unterscheiden sich nach ihrer Anzahl Bytes, das heißt, die Datentypen können verschieden große Zahlen aufnehmen.

  • Bei den Fließkommazahlen haben wir float und double zur Verfügung; ein double hat doppelt so viele Bits wie ein float zum Speichern.

Die Größe der Datentypen ist in der Java-Spezifikation festgeschrieben und nicht abhängig von der jeweiligen Architektur oder Plattform.

1.2.1. Auf Variablen zugreifen und Belegung ausgeben ⭐

Captain CiaoCiao möchte Zielscheiben für Neulinge, Fortgeschrittene und Profis herstellen. Die Zielscheiben sind unterschiedlich groß.

Ein Kreis ist beschrieben durch Koordinaten und einen Radius. Unser erstes Programm hat den Kreismittelpunkt und Radius fest eingebaut, nun wollen wir die Ausgabe parametrisierbar machen.

Ergänze aus der vorangehenden Aufgabe die main(…​)-Methode.

Aufgabe:

  • Deklariere in der main(…​)-Methode zwei int-Variablen x, y und eine double-Variable r.

  • Belege die Variablen mit Werten.

  • Baue die Belegung der Variablen in die Ausgabe ein.

Beispiel:

  • Ist etwa x = 100 und y = 110 und r = 20.5, dann soll auf der Konsole ausgegeben werden:

    <svg height="100" width="1000">
     <circle cx="100" cy="110" r="20.5" />
    </svg>
  • Bei der manuellen Belegung mit x = 10, y = 10 und r = 2.686:

    <svg height="100" width="1000">
     <circle cx="10" cy="10" r="2.686" />
    </svg>

Es entsteht ein schwarzer Kreis auf weißem Grund.

1.2.2. Zufallszahlen bilden und verschiedene Kreise generieren ⭐

Zufallszahlen spielen in der Praxis eine größere Rolle, als man auf den ersten Blick vermuten könnte.

In Java gibt es eine Klasse Math, die wichtige mathematische Methoden bereitstellt. Zufallszahlen können so ermittelt werden:

double rnd = Math.random();

Die Methode random() ist demnach ein Angebot der Math-Klasse.

Aufgabe:

  • Lies in der Javadoc nach, in welchem Wertebereich das Ergebnis von random() ist.

  • Erweitere das Kreisprogramm, sodass der Radius zufällig ist, und zwar im Bereich von einschließlich 10, aber echt kleiner 20. Der Radius bleibe weiterhin eine Fließkommazahl.

Beispiel:

  • Wenn wir das Programm zweimal starten, könnten die Ausgaben so aussehen:

    <svg height="100" width="1000">
     <circle cx="100" cy="110" r="19.47493300792351" />
    </svg>
    <svg height="100" width="1000">
     <circle cx="100" cy="110" r="10.218243515543868" />
    </svg>

Alternative Varianten zum Bilden von Zufallszahlen in Java sind:

double rnd1 = java.util.concurrent.ThreadLocalRandom.current().nextDouble();
double rnd2 = java.util.concurrent.ThreadLocalRandom.current().nextDouble(/* 0 bis */ max);
double rnd3 = java.util.concurrent.ThreadLocalRandom.current().nextDouble(min, max);
int    rnd4 = java.util.concurrent.ThreadLocalRandom.current().nextInt();
int    rnd5 = java.util.concurrent.ThreadLocalRandom.current().nextInt(/* 0 bis */max);
int    rnd6 = java.util.concurrent.ThreadLocalRandom.current().nextInt(min, max);

1.2.3. Benutzereingaben verarbeiten ⭐

Bisher haben wir Bildschirmausgaben vorgenommen, aber noch keine Eingaben angenommen.

Mithilfe von new java.util.Scanner(System.in).next*() lassen sich Eingaben von der Kommandozeile annehmen. Beispiele:

int    number1 = new java.util.Scanner( System.in ).nextInt();
double number2 = new java.util.Scanner( System.in ).nextDouble();
String line    = new java.util.Scanner( System.in ).nextLine();

Captain CiaoCiao möchte die Position des SVG-Kreises selbst bestimmen können.

Aufgabe:

  • Nimm für den Kreis die Belegungen für cx und cy als Ganzzahlen von der Konsole an, und schreibe das generierte SVG-Fragment wieder in die Standardausgabe. Der Radius bleibt weiterhin zufällig.

1.3. Ausdrücke, Operanden und Operatoren

Ein Ausdruck wird ausgewertet und ergibt ein Ergebnis. Mit Operatoren lassen sich Operanden wie Literale oder Variablen verknüpfen.

1.3.1. Zahlen vergleichen und Geld zusammen? ⭐

Die drei Banditen Cosimo Fatface, Lucia Rubberneck und Slick Foot Vito schulden Bonny Brain zusammen 1 Million Liretta.

  1. Schreibe ein Programm, was drei Fließkommazahlen mit new java.util.Scanner(System.in).nextDouble() erfragt und in Variablen speichert.

  2. Gibt true oder false aus, ob die drei die Summe von 1 Million aufbringen können.

1.3.2. Prüfen, ob Beute fair aufgeteilt werden kann ⭐

Nach einem Raubzug in der Schnapsbrennerei erbeuten Captain CiaoCiao und seine Crew unzählige Flaschen. Jetzt muss die Beute aufgeteilt werden, wobei Captain CiaoCiao grundsätzlich die Hälfte bekommt (bei einer ungeraden Anzahl Flaschen bekommt er weniger als die Hälfte, so großzügig ist der Captain). Alle anderen Räuber sollen exakt den gleichen Anteil bekommen. Aber geht das auf?

Aufgabe:

  • Schreibe ein Programm, das die erbeutete Anzahl Flaschen von der Kommandozeile einliest und ausgibt, wie viel Captain CiaoCiao davon bekommt.

  • Gib aus, was für die Crew verbleibt.

  • Frage nach der Crewgröße, und prüfe, ob die Beute fair und gleich verteilt werden kann, sodass jedes Crewmitglied exakt die gleiche Anzahl Flaschen bekommt. Eine Antwort in der Form true oder false reicht.

Beispiel:

Number of bottles in total?
123000
Bottles for the captain: 61500
Bottles for all crew members: 61500
Number of crew members?
100
Fair share without remainder? true

Überlege wie sich Division und Restwert verhalten.

1.3.3. Besitzen zwei Zahlen gleiche Ziffern? ⭐⭐

Bonny Brain spielt Anker-Domino, und alle Spielsteine haben zwei Felder, mit Werten 0 bis 9. Jetzt möchte sie wissen, ob — auch durch Rotation — zwei Spielsteine so aneinandergelegt werden können, dass die beiden Felder die gleichen Werte haben.

Aufgabe:

  1. Schreibe ein Programm, das zwei Zahlen einliest, wobei die Zahlen im Bereich von 0 bis 99 (beide Grenzen inklusive) liegen sollen.

  2. Sind die Zahlen über 100, sollen nur die letzten zwei Ziffern gewertet werden; 100 oder 200 wären dann wie 00 (also 0), 1111 wäre wie 11.

  3. Teste, ob die beiden Zahlen eine gemeinsame Ziffer haben.

Beispiele:

  • 12 und 31 haben 1 als gemeinsame Ziffer.

  • 22 und 33 haben keine gemeinsame Ziffer.

Hinweis: Es ist nicht die gemeinsame Ziffer gefragt, sondern einfach nur eine Ausgabe true/false. Ist die Zahl einstellig, steht vorne gedanklich eine 0, sodass 01 und 20 eine Gemeinsamkeit haben, nämlich 0.

1.3.4. Währungsbetrag in Münzen umrechnen ⭐⭐

In der Währung Liretta gibt es Lirettamünzen mit den Nennwerten 2 Liretta, 1 Liretta, 50 Lirettacent, 20 Lirettacent, 10 Lirettacent, 5 Lirettacent, 2 Lirettacent und 1 Lirettacent. 100 Lirettacent entsprechen 1 Liretta.

CoinMachine

Aufgabe:

  1. Lege eine neue Klasse CoinMachine an.

  2. Das Programm soll als Erstes eine Fließkommazahl für einen Geldbetrag fordern.

  3. Gibt aus, wie der eingegebene Betrag in Lierettamünzen ausgezahlt werden kann. Es sind nicht alle Permutationen gewünscht, sondern nur die kleinste Anzahl Münzen.

Beispiel mit Eingabe 12,91:

Please enter amount of money:
12,91
6 x 2 Liretta
0 x 1 Liretta
1 x 50 Lirettacent
2 x 20 Lirettacent
0 x 10 Lirettacent
0 x 5 Lirettacent
0 x 2 Lirettacent
1 x 1 Lirettacent

Die Formatierung der Ausgabe spielt keine Rolle.

Der Scanner ist lokalisiert, nutzt also bei der Eingabe von Nachkommenstellen den Dezimaltrennzeichen der jeweiligen Sprache. Das heißt, auf deutschen Systemen muss die Fließkommazahl mit einem Komma statt eines Punktes eingegeben werden.

1.3.5. Eine Flasche Rum, 10 Flaschen Rum ⭐

Bonny Brain ist eine Jägerin der falschen Sprache, und sie achtet immer darauf, dass Beschriftungen grammatikalisch korrekt sind. Die Regeln für den Plural sind in vielen Sprachen besonders, denn es heißt zum Beispiel »1 Flasche« oder »99 Flaschen«, aber auch »0 Flaschen«. Oftmals finden sich in Oberflächen Vereinfachungen wie »1 Flasche(n)«.

One bottle of rum 10 bottles of rum

Aufgabe:

  • Lege eine Variable noOfBottles an und belege sie mit einem Wert größer gleich 0.

  • Programmiere eine grammatikalisch korrekte Ausgabe, abhängig davon, ob es 0, 1 oder viele Flaschen gibt.

Beispiel:

  • "0 bottles of rum"

  • "1 bottle of rum"

  • "99 bottles of rum"

Der Bedingungsoperator (?-:-Operator) macht den Code kompakt.

1.4. Fallunterscheidungen

Wenn-dann-Beziehungen sind wichtige imperative Konzepte. Wir nutzen diese Möglichkeit, aufgrund von Bedingungen Programmteile abzuarbeiten oder nicht, für die folgenden Aufgaben, um Benutzereingaben zu prüfen und zu verarbeiten.

1.4.1. Zahltag ⭐

Bonny Brain hat Tort Ellini eine antike Taschenuhr für 1.000 Liretta verkauft. Tort muss nun die Uhr bezahlen.

Payday

Aufgabe:

  1. Schreibe ein Programm, das auf der Kommandozeile mit new java.util.Scanner(System.in).nextDouble() den Betrag der Rückzahlung einliest.

  2. Bonny Brain ist immer guter Laune, daher ist sie auch mit 10 % weniger zufrieden. Auch fühlt sie sich gebauchpinselt, wenn Tort 20 % mehr gibt. Zahlt Tort allerdings freiwillig über 20 % mehr, hat Bonny Brain den Eindruck, dass etwas nicht stimmt und die Taschenuhr wohl eine wertvolle versteckte Funktion hat oder ein Geheimnis birgt. Überlege, wie man das Programm so aufbaut, dass wenig Codeänderungen nötig sind, wenn die Grenzen sich aus einer Laune heraus verschieben.

  3. Wenn Tort den passenden Betrag beisammenhat, erscheint auf dem Bildschirm "Good boy!", bei einem zu niedrigen Betrag oder einem Versuch der Bestechung kommt "You son of a bi***!".

1.4.2. Literangaben umrechnen ⭐⭐

Ein Programm soll Flüssigkeitsmengen in eine für Captain CiaoCiao leicht lesbare Form umwandeln.

Aufgabe:

  • Lies von der Kommandozeile eine Fließkommazahl ein, die Größenordnung ist Liter.

  • Konvertiere die Zahl nach folgendem Muster:

    • 1,0 und größer: Ausgabe in Liter, etwa ca. 4 l bei der Eingabe 4

    • 0,1 und größer: Ausgabe in Zentiliter, etwa ca. 20 cl bei der Eingabe 0,2

    • 0,001 und größer: Ausgabe in Milliliter, etwa ca. 9 ml bei der Eingabe 0,009

  • Die Ausgabe ist immer eine Ganzzahl. Rundungen sind in Ordnung.

Beispiel:

  • Umrechnung in ml:

    Enter quantity in liters:
    0,0124134
    approx. 12 ml
  • Umrechnung in cl:

    Enter quantity in liters:
    0,9876
    approx. 98 cl
  • Meldung bei zu kleinem Wert:

    Enter quantity in liters:
    0,00003435
    Value too small to display
  • Eingabe ist schon in Liter:

    Enter quantity in liters:
    98848548485,445
    approx. 98848548485 l

1.4.3. SVG-Kreise mit zufälligen Farben erzeugen ⭐

In einer früheren Aufgabe hat Captain CiaoCiao einen schwarzen Kreis auf weißem Grund eingefordert. Doch etwas Farbe dürfte es schon sein!

Aufgabe:

  • Lege eine neue Klasse mit einer main(…​)-Methode an.

  • Gib auf der Kommandozeile zufällig, und mit gleicher Wahrscheinlichkeit, red, green, blue aus.

  • In SVG kann man bei Kreisen die Farbe mit dem Attribut fill bestimmen, etwa so: <circle cx="20" cy="20" r="5" fill="blue" />. Gib dem Kreis eine zufällige Farbe.

Beispiel:

  • Bei drei Programmstarts könnte es folgende Bildschirmausgaben geben:

    <circle cx="20" cy="20" r="5" fill="green" />
    <circle cx="20" cy="20" r="5" fill="blue" />
    <circle cx="20" cy="20" r="5" fill="blue" />

1.4.4. Eingegebene Zeichenfolgen für eine Zustimmung auswerten ⭐

Bonny Brain erwartet Zustimmung für neue Projekte, und die Bejahung kann unterschiedlich erfolgen.

Aufgabe:

  • Erfrage von der Kommandozeile eine Zeichenkette. Wir nehmen an, das die Eingabe immer kleingeschrieben erfolgt.

  • Ist die Zeichenkette "ay", "aye", "ay, ay", "ja" oder "joo", soll "Keep it up!" auf dem Bildschirm ausgegeben werden, alle andere Zeichenfolgen führen zur Ausgabe "Don’t you dare!".

  • Löse die Aufgabe mit der switch-Anweisung oder dem switch-Ausdruck.

1.4.5. switch-Anweisung in switch-Ausdruck umschreiben ⭐

In Java 14 wurde die Syntax für switch erweitert, sodass manch alter Code kompakter geschrieben werden kann.

Aufgabe:

  • Gegeben ist folgender Code mit der klassischen switch-Anweisung:

    int month = new java.util.Scanner( System.in ).nextInt();
    int year = new java.util.Scanner( System.in ).nextInt();
    boolean isLeapYear =    ((year % 4 == 0) && (year % 100 != 0))
                         || (year % 400 == 0);
    
    int days;
    switch ( month ) {
      case 2:
        days = isLeapYear ? 29 : 28;
        break;
      case 4:
      case 6:
      case 9:
      case 11:
        days = 30;
        break;
      default:
        days = 31;
    }
  • Verkürze das Programm mit dem switch-Ausdruck.

1.5. Schleifen

Neben Fallunterscheidungen sind Wiederholungen die zweite wichtige imperative Eigenschaft. Java bietet unterschiedliche Sprachkonstrukte für Schleifen:

  • while-Schleife

  • do-while-Schleife

  • for-Schleife

  • erweiterte for-Schleife

1.5.1. Rotierte SVG-Rechtecke erzeugen ⭐

Nach einem Beutezug kommt Captain CiaoCiao oft gestresst zurück. Um sich zu entspannen, malt er geometrische, wiederkehrende Muster aus. Bonny Brain soll für ihn Blätter vorbereiten, doch drauf hat sie keine Lust; ein Programm soll das erledigen.

SvgRotatingRect

Folgende Vektorgrafik in SVG rotiert ein Rechteck um den Mittelpunkt (100, 100), und zwar um 60 Grad:

<svg height="200" width="200">
 <rect x="50" y="50" width="100" height="100" stroke="black" fill="none"
       transform="rotate(60 100 100)" />
</svg>

Aufgabe:

  • Schreibe ein Programm, das 36 SVG-Rechtecke rotiert um 10 Grad übereinandersetzt und auf dem Bildschirm ausgibt.

  • Schreibe das Programm so, das man prinzipiell den Rotationswinkel anpassen kann.

Beispiel:

  • Die Ausgabe beginnt mit:

    <svg height="200" width="200">
     <rect x="50" y="50" width="100" height="100" stroke="black" fill="none" transform="rotate(0 100 100)" />
     <rect x="50" y="50" width="100" height="100" stroke="black" fill="none" transform="rotate(10 100 100)" />
     <rect x="50" y="50" width="100" height="100" stroke="black" fill="none" transform="rotate(20 100 100)" />
    ...

1.5.2. SVG-Perlenkette erzeugen ⭐

Captain CiaoCiao möchte seiner geliebten Bonny Brain eine Perlenkette schenken. Diese soll aus drei verschiedenen Edelsteinen bestehen: Saphir (blau), Smaragd (grün), Spessartit-Granat (orange). Er möchte einen Designvorschlag haben, in dem die Farben zufällig angeordnet werden.

BonnysPearls

Folgendes steht für ein SVG-Dokument mit drei Kreisen:

<svg height="100" width="1000">
 <circle cx="20" cy="20" r="5" fill="blue" />
 <circle cx="30" cy="20" r="5" fill="green" />
 <circle cx="40" cy="20" r="5" fill="orange" />
</svg>

Aufgabe:

  • Erzeuge eine SVG-Ausgabe auf der Kommandozeile, in der 50 Kreise nebeneinanderstehen.

1.5.3. Zahlen von der Kommandozeile summieren ⭐

Captain CiaoCiao möchte ein Programm, in das er die Anzahl erbeuteter Liretta aus seinen einzelnen Raubzügen auf der Kommandozeile eingeben kann und das diese addiert.

Sum numbers from the command line

Aufgabe:

  • Lege eine neue Klasse SummingCalculator an.

  • Nimm über den Scanner so lange Zahlen entgegen, bis 0 eingegeben wird. Negative Zahlen sind ebenfalls erlaubt, weil Captain CiaoCiao auch — wenn auch selten — ausgeraubt wird. Ignoriere mögliche Überläufe durch zu große Zahlen.

  • Nachdem 0 eingegeben wird, soll die Summe ausgegeben werden.

Beispiel:

12
3
-1
0
Sum: 14

1.5.4. Ein mathematisches Phänomen durchlaufen ⭐

Eine Iteration ist in der Mathematik eine wiederholte Berechnung beginnend mit einem Startwert, bis eine bestimmte Bedingung erfüllt ist. Bei Berechnungen sind Iterationen ein wichtiges Verfahren, um nach einer ersten Näherung bei jedem zusätzlichen Schritt die Lösung zu verbessern.

Aufgabe:

  • Deklariere eine double-Variable t zwischen 0 (inklusiv) und 10 (exklusiv) mit folgender Zeile:

    double t = Math.random() * 10;
  • Multipliziere t mit 2, wenn t < 1. Wenn jedoch t >= 1 ist, ziehe 1 ab.

  • Setze diese Berechnung in eine while-Schleife, die enden soll, wenn t kleiner gleich 0 ist.

Beispiel:

  • Die Ausgabe könnte sich so entwickeln:

    9.835060881347246
    8.835060881347246
    7.835060881347246
    6.835060881347246
    ...
    0.75
    1.5
    0.5
    1.0

1.5.5. Produkte für Fakultäten berechnen ⭐

Für die neue Flotte Rigel VII muss Bonny Brain die Führungsoffiziere auswählen; zur Auswahl stehen Paul Peldrion, Kate Muggl, Robinson Langdon, Lienn Langdon. Allerdings ist sich Bonny Brain unsicher, welche Person welche Rolle einnehmen soll; es gibt: Kommandant, Erster Offizier, Zweiter Offizier, Dritter Offizier.

Es gibt viele Möglichkeiten, welche Person welche Rolle einnimmt. Wie viele mögliche Anordnungen von verschiedenen Elementen es in einer Reihe gibt, sagt die sogenannte Permutation aus. Eine Permutation ohne Wiederholung wird berechnet über die Fakultät. Bei vier Personen gibt es 1 × 2 × 3 × 4 = 24 mögliche Anordnungen.

Die Fakultät einer natürlichen Zahl (positive ganze Zahl) wird über das Produkt der Zahlen nach folgendem Muster gebildet:

n! = 1 × 2 × 3 × … × (n − 1) × n

Es gilt 0! = 1.

Aufgabe:

  • Schreibe ein Java-Programm, das von der Kommandozeile eine nichtnegative ganze Zahl einliest und die Berechnung anzeigt.

Beispiel:

  • Eingabe: 9 → Ausgabe: 9! = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 = 362880

  • Eingabe: 3 → Ausgabe: 3! = 1 * 2 * 3 = 6

  • Eingabe: 0 → Ausgabe: 0! = 1

  • Eingabe: 1 → Ausgabe: 1! = 1

  • Eingabe: -1 → Ausgabe: Number must not be negative

Nutze intern den Datentyp long.

Frage: Ab welcher Zahl gibt es »Probleme«? Wie fallen die »Probleme« auf, und wie können wir die Probleme erkennen? Kann uns Math.multiplyExact(long x, long y) helfen?

1.5.6. Feststellen, ob eine Zahl durch Fakultät gebildet wurde ⭐

Jar Jar Dumbs hat von Bonny Brain den Auftrag bekommen, für eine gegebene Anzahl Personen alle möglichen Anordnungen aufzuschreiben. Bevor sie sich die Liste anschaut, zählt sie die Anzahl, um festzustellen, ob alle Permutationen aufgeführt wurden.

Determine if a number is formed by factorial

Wie wir für eine natürliche Zahl die Fakultät berechnen, haben wir in der vorherigen Aufgabe gesehen. Doch wie können wir herausfinden, ob eine Zahl eine Fakultät ist? Wir wissen, dass 9! = 362880 ist, aber was ist mit 212880 oder 28?

Aufgabe:

  • Schreibe ein Programm, das eine natürliche Zahl von der Kommandozeile einliest, und ausgibt, ob die Zahl eine Fakultät darstellt.

Beispiel:

  • Zahl ist Fakultät:

    Enter a number:
    362880
    362880 = 9!
  • Zahl ist keine Fakultät:

    Enter a number:
    1000
    1000 is not a factorial

Teste, ob die Zahl durch 2, 3, 4, 5 …​ teilbar ist.

1.5.7. Kleinste und größte Ziffer einer Zahl finden ⭐

Bonny Brain weiß natürlich, dass Dezimalzahlen aus Ziffern von 0 bis 9 bestehen. Da die Fahrt mit dem Schiff lang und langweilig ist, hat sie sich ein Spiel ausgedacht: Sie nennt der Mannschaft eine Ganzzahl, und wer am schnellsten deren größte und kleinste Ziffer nennt, erhält eine Liretta.

Find smallest largest digit number

Aufgabe:

  • Gegeben ist eine beliebige Ganzzahl (positiv oder negativ), gespeichert in einem long.

  • Hilf mit einem Programm, die kleinste und größte Ziffer der gespeicherten Zahl zu ermitteln.

Beispiele:

  • 12345 → 1, 5

  • 987654 → 4, 9

  • 11111 → 1, 1

  • 0 → 0, 0

  • -23456788888234567L → 2, 8

1.5.8. Ein Wimpel im Wind durch geschachtelte Schleifen ⭐

Nach einem harten Seegang stellt die Crew fest, dass eine Flagge fehlt. Captain CiaoCiao bittet seiner Crew Ersatz zu schaffen.

flag in the wind through nested loops

Aufgabe:

  • Erzeuge folgende Ausgabe, die so aussieht wie eine kleine Flagge:

    1
    2 2
    3 3 3
    4 4 4 4
    5 5 5 5 5

Optional: Die Ausgabe soll als in dem Sinne als Baum erscheinen, dass alle Zeilen zentriert sind.

1.5.9. Einfaches Schachbrett ausgeben ⭐

Captain CiaoCiao liebt die Deutsche Dame — eine Variante des Damespiels. Er nimmt regelmäßig an Wettbewerben teil und stellt fest, dass das Spielbrett manchmal unterschiedlich groß ist. Mal sind es 8 × 8 Felder, mal 10 × 10 Felder, auch 12 × 12 und 14 × 14 hat er schon erlebt.

Damit sich Captain CiaoCiao auf alle möglichen Spielfeldgrößen vorbereiten kann, soll ein Programm ein Schachbrett auf dem Bildschirm ausgeben.

Output simple chessboard

Aufgabe:

  • Erfrage von der Kommandozeile Höhe und Breite des Spielbretts.

  • Zeichne das Spielbrett nach den Größenangaben aus den Symbolen # und _.

Beispiel:

Checkerboard width: 10
Checkerboard height: 5
_#_#_#_#_#
#_#_#_#_#_
_#_#_#_#_#
#_#_#_#_#_
_#_#_#_#_#

1.5.10. Es weihnachtet sehr: Bäume mit Schmuck darstellen ⭐

Bald ist Weihnachten, und Bonny Brain möchte Weihnachtskarten drucken. Dafür sind Bäume unterschiedlicher Größe nötig.

Its Christmastime Displaying trees with ornaments

Aufgabe:

  • Schreibe über Schleifen eine dreieckige Baumkrone mit einer maximalen Breite width auf den Bildschirm.

  • In jeder Zeile wird der String um 2 Zeichen länger, bis er >= width wird.

  • Die Zentrierung wird über vorangesetzte Leerzeichen erreicht.

  • Die Blätter des Baumes bestehen aus dem Multiplikationszeichen *.

  • Streue zufällig in den Baum o-Zeichen ein, die Weihnachtskugeln repräsentieren.

Beispiel:

  • Baum mit der Breite 7 (gleich mit einem Baum der Breite 8):

       *
      *o*
     ***o*
    *o*****

1.5.11. Fischige Stickmotive zeichnen ⭐

Bonny Brain liebt das Meer und wünscht sich ein Tuch mit Fischmuster. Die Nähmaschine kann mit den Symbolen < und > die Motive ><> und <>< sticken.

Folgendes bildet ein Muster mit einer Wiederholung von 1, sodass erst ein Fisch nach rechts und dann ein Fisch nach links schwimmt.

><>   <><
Draw fishy stitching motifs

Aufgabe:

  • Schreibe ein Programm, das gemäß der Belegung einer Variablen repetitions erst den Fisch ><> repetitions-mal hintereinandersetzt und dann den Fisch <>< repetitions mal hintereinandersetzt . Die Zeile soll selbst repetitions oft untereinanderstehen.

Beispiele:

  • Ist repetitions gleich 2, soll die Ausgabe sein:

    ><>   ><>   <><   <><
    ><>   ><>   <><   <><
  • Ist repetitions = 3 soll das Programm zu folgender Ausgabe führen:

    ><>   ><>   ><>   <><   <><   <><
    ><>   ><>   ><>   <><   <><   <><
    ><>   ><>   ><>   <><   <><   <><

1.5.12. Ausprobieren statt Denken ⭐⭐

Ein Computer ist so schnell, dass er gewisse Dinge einfach ausprobieren kann. Passwort-Knackprogramme arbeiten nach diesem Prinzip.

Captain CiaoCiao blättert in der »Pirates Daily« und findet eine Denksportaufgabe:

X

O

L

+

L

X

X

=

T

L

T

Er muss für die Buchstaben L, O, T und X jeweils eine Ziffer finden, damit die Rechnung stimmt. Der Preis für das Rätsel ist ein alter Kompass, den will Captain CiaoCiao unbedingt gewinnen. Doch leider fehlt ihm die Lust zu denken.

Trying instead of thinking

Aufgabe:

  • Entwickele ein Programm, das durch Ausprobieren aller Möglichkeiten eine Lösung findet.

  • Gib alle Lösungen aus, und markiere die Lösungen, in denen X, O, L und T alle unterschiedlich sind.

1.5.13. Anzahl Ziffern einer Zahl ermitteln ⭐⭐

Bonny Brain möchte Zahlen rechtsbündig setzen. Dafür werden vor die Zahlen Leerzeichen gesetzt. Möchten Sie etwa die Breite von 10 Zeichen haben und lautet die Zahl 123 (drei Ziffern), dann müssen sieben Leerzeichen vor die Zahl gesetzt werden, damit die Breite 10 wird.

Der erste Schritt, um die Anzahl Leerzeichen zu ermitteln, ist, die Anzahl Ziffern einer Zahl zu bestimmen.

Aufgabe:

  • Gegeben ist eine positive Ganzzahl n vom Typ int. Gib die Anzahl Ziffern der Zahl aus. Nutze nicht (""+n).length(), das wäre zu einfach …​

Beispiele für n und die erwartete Ausgabe:

  • 12344

  • 31

  • 01

  • Integer.MAX_VALUE10

1.6. Methoden

Methoden sind wichtig, weil wir auf diese Weise gemeinsamen Code zentralisieren und auch Objekte eine API zum Zugriff für Clients geben können.

1.6.1. Herzen zeichnen ⭐

Da Captain CiaoCiao seine Besatzung liebt, kann es nicht genug Herzen geben.

Drawing hearts

Aufgabe:

  1. Lege eine neue Klasse LinePrinter an. Setze in die Klasse eine statische Methode line(), die eine Linie aus zehn Herzen schreibt. Das Unicode-Zeichen "♥" kann Java in Strings speichern und ausgeben.

  2. Lege eine neue Klasse LinePrinterDemo an, die eine main(…​)-Methode hat und line() aufruft.

1.6.2. Überladene Linien-Methoden implementieren ⭐

Als Nächstes wollen wir uns mit Methoden beschäftigen, denen man etwas mitgeben kann. Außerdem kann ein Methodenname mehrfach verwendet werden: Wir sprechen von überladenen Methoden.

Aufgabe:

  • Eine Methode line(int len) soll eine Linie der Länge len mit Minuszeichen ("-") auf der Konsole ausgeben, also würde line(3) auf dem Bildschirm --- ausgeben.

  • Die Methode line(int len, char c) soll man mit eigenen Füllzeichen aufrufen können. So gibt line(2, 'x') die Linie xx auf dem Bildschirm aus. Kann die erste Methode die zweite nutzen?

  • Setze eine weitere überladene Methode line(String prefix, int len, char c, String suffix) hinzu, die vor der Linie einen Start-String und nach der Linie einen End-String setzt. Beispiel: line("╠", 3, '═', "╣") liefert ╠═══╣. Die Linie im Inneren ist 3 Zeichen lang, nicht der gesamte String.

Bedenke: Nicht alle drei Methoden muss man komplett mit einer Schleife implementieren. Wer clever ist, leitet von einer Methode auf die andere Methode weiter.

Füge die überladenen Methoden der Klasse LinePrinter hinzu.

Optional: Implementiere line(int len, String s), die Strings nebeneinander setzt, aber bis zur maximalen Länge len. Mit s.length() bekommt man die Länge eines Strings s und mit s.charAt(int index) an ein Zeichen an der Stelle index; der Index beginnt bei 0. Beachte die korrekte Länge, zum Beispiel beim Aufruf von

line( 5, "*=" );    // ist das Ergebnis *=*=*

1.6.3. Alles im Lot ⭐

In der Vergangenheit haben die Einfaltspinsel unter Bonny Brain den Mast schief aufgestellt. Ein Pirat muss nicht immer senkrecht stehen, der Mast aber schon!

Standing straight

Nimmt man ein Dreieck, so kann es in verschiedenen Formen auftauchen. Es gibt unter anderem spitzwinklige Dreiecke, stumpfwinklige Dreiecke, gleichseitige Dreiecke und rechtwinklige Dreiecke. Zur Erinnerung: Dreiecke sind rechtwinklig, wenn c2 = a2 + b2 ist.

Aufgabe:

  • Lege eine neue Klasse RightTriangle an und schreibe eine neue Methode; nutze folgenden Code als Vorlage:

    class RightTriangle {
      public static boolean isRightTriangle( double a, double b, double c ) {
        // Your implementation goes here
      }
    }
  • Die Methode soll drei Seiten eines Dreiecks annehmen und true als Rückgabe liefern, wenn es sich um ein rechtwinkliges Dreieck handelt, andernfalls false.

  • Bedenke: Jeder Parameter a, b, c kann für die Katheten oder Hypotenuse stehen.

Beispiel:

  • isRightTriangle(3, 4, 5)true

  • isRightTriangle(5, 4, 3)true

  • isRightTriangle(5, 12, 13)true

  • isRightTriangle(1, 2, 3)false

  • isRightTriangle(1, 1, Math.sqrt(2))false

Am letzten Beispiel lässt sich gut ablesen, dass die Rechenungenauigkeit ein Problem ist. Math.sqrt(2) * Math.sqrt(2) ist (in der Ausgabe) 2.0000000000000004 und eben nicht genau 2.

1.6.4. Ist das Kunst, oder kann das weg — der Weg zum Pointillismus ⭐⭐

Wirf einen Blick auf das Bild unter https://www.artists.de/281604-hommage-au-pointillismus. Wir wollen uns auch 2900 € verdienen, und das Bild in Java mit SVG nachzeichnen.

  1. Studiere https://tutego.de/go/trysvgcircle und schreibe ein Java-Programm, das SVG auf dem Bildschirm ausgibt für genau einen Kreis.

  2. Zeichne eine einzelne Reihe mit Kreisen.

  3. Zeichne ein Rechteck mit Kreisen. Überlege, wie die Kreise versetzt werden.

  4. Gib jedem Kreis zufällig einen von sechs festen Farben.

  5. Schaue nach, wie das "Bild" eine Hintergrundfarbe bekommen kann.

  6. Überlege, wie man das Programm in mehrere Methoden aufteilt.

1.6.5. Multiplikationstabelle erstellen ⭐

Bonny Brain hat in der Magical Company zwei neue Produkte aufgenommen: Flammenwerfer (englisch flamethrower) und Feuerlöscher (englisch fire extinguisher). Der Flammenwerfer kostet 500 Liretta, der Feuerlöscher kostet 100 Liretta.

Um bei einer größeren Abnahme schnell ablesen zu können, wie hoch der Preis ist, soll eine Tabelle in HTML erzeugt werden:

QuantityFlamethrowerFire extinguisher

1

500

100

2

1000

200

3

1500

300

…​

…​

…​

In HTML wird eine Tabelle wie folgt darstellt:

<html>
<table>
<tr><th>Quantity</th><th>Flamethrower</th></tr>
<tr><td>1</td><td>500</td></tr>
<tr><td>2</td><td>1000</td></tr>
</table>
</html>

Aufgabe:

  • Erzeuge auf dem Bildschirm die gezeigte HTML-Tabelle mit der Anzahl 1 bis 10.

  • Überlege, wo eigene Methoden sinnvoll sind.

Sie können das generierte HTML unter https://jsfiddle.net/ kopieren und »ausführen«, um das Ergebnis zu sehen.

1.6.6. Zisterzienser Zahlschrift ⭐⭐⭐

Eine Zahlschrift ist eine Schrift, die aus Symbolen besteht, die als Zahlen verwendet werden. Es gibt verschiedene Arten von Zahlschriften, die in verschiedenen Kulturen und Zeitperioden verwendet wurden. Beispiele sind die römische Zahlschrift (MCMLXXIII wäre 1973) und die Arabische Zahlschrift mit den bekannten Ziffern 0, 1, 2, 3, 4, 5, 6, 7, 8 und 9, die heute in den weltweit meisten Teilen verwendet wird.

Der Zisterzienser-Orden ist bekannt für die Zisterzienser Zahlschrift, in der die Zahlen von 1 bis 9999 in einem einzigen Zeichen ausdrückt werden kann. Der Bauplan ist wie folgt:

Cistercian digits vertical
Abbildung 2. Zisterzienser Zahlen

Ein paar Beispiele:

Cistercian digits examples
Abbildung 3. Beispiele für Zisterzienser Zahlen

Aufgabe:

  • Schreibe ein Programm, das für eine beliebige vierstellige Zahl nach dem vorgestellten Muster SVG auf der Kommandozeile generiert.

Beispiel:

  • Für 9394 könnte folgendes SVG entstehen:

    <svg height="1400" width="1400">
    <g style="stroke:grey;stroke-linecap:round;stroke-width:2">
    <line x1="100" y1="85" x2="100" y2="115" />
    <line x1="100" y1="95" x2="110" y2="85" />
    <line x1="100" y1="85" x2="90" y2="85" />
    <line x1="100" y1="95" x2="90" y2="95" />
    <line x1="90" y1="85" x2="90" y2="95" />
    <line x1="100" y1="115" x2="110" y2="105" />
    <line x1="100" y1="115" x2="90" y2="115" />
    <line x1="100" y1="105" x2="90" y2="105" />
    <line x1="90" y1="115" x2="90" y2="105" />
    </g>
    </svg>
  • https://upload.wikimedia.org/wikipedia/commons/0/0b/Cistercian1-9999.png zeigt alle möglichen Zeichen.

Beachte die horizontale und vertikale Spiegelung.

1.6.7. Quiz: Was macht Ding-Dong? (Rekursion) ⭐⭐

In einem längst verschollenen Programm taucht folgende Methode auf:

static long ding( long dong ) {
  return dong == 0 ? 0
                   : (dong % 10 + ding( dong / 10 ));
}

Was macht die Methode? Wie könnte sie besser benannt werden?

1.6.8. Quiz: Schnapszahl (Rekursion) ⭐⭐

Eine Schnapszahl hat nur identische Ziffern. In der Mathematik werden diese Zahlen auch als Repdigit (von repeated digits) bezeichnet.

Folgende Java-Methode ermittelt auf rekursive Weise, ob eine Zahl eine Schnappszahl ist:

static boolean isRepdigit( long n ) {
  if ( (n % 100) / 10 != n % 10 )
    return n < 10;
  return isRepdigit( n / 10 );
}

Aufgabe:

  • Wie funktioniert die Methode?

  • In der Fallunterscheidung lässt sich die Bedingung

    (n % 100) / 10 != n % 10

    umformulieren zu

    n % 100 % 11 != 0

    Warum?

1.6.9. Collatz-Folge berechnen (Rekursion) ⭐

Lothar Collatz definierte 1937 eine Zahlenfolge, die heute als Collatz-Folge bekannt ist. Sie wird wie folgt als Abbildung definiert, dass auf eine Zahl n folgt:

  • nn/2, falls n gerade ist,

  • n → 3n + 1, falls n ungerade ist.

  • Die Folge ist beendet, wenn 1 erreicht ist.

Beginnen wir etwa mit n = 7, durchläuft der Algorithmus die folgenden Zahlen:

  • 7 → 22 → 11 → 34 → 17 → 52 → 26 → 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

Jede Folge endet auf 4, 2, 1, aber warum das so ist, ist bis heute ungeklärt und ein ungelöstes Problem der Mathematik.

Aufgabe:

  • Lege eine Klasse Collatz mit einer Methode void collatz(long n) an.

  • Erstelle eine main(…​)-Methode, und berechne die Collatz-Folge für den Startwert 27.

  • Schreibe eine neue Methode long collatzMax(long n), die den jeweils größten erreichten Zwischenwert zurückgibt.

  • Wie können wir collatz(…​) rekursiv programmieren, sodass die Methode als Ergebnis den maximal angenommenen Wert liefert? Achtung, die Signatur muss geändert werden! (Warum?)

1.6.10. Bauernmultiplikation (Rekursion) ⭐⭐

Arithmetische Operationen sind eines der Kernaufgaben von Computern. Additionen und Subtraktionen sind einfach, auch die Multiplikation und Division durch zwei, weil das durch eine Verschiebung der Bits nach links und rechts realisiert werden kann.

Multiplikationen wurden von den früheren Prozessoren nicht implementiert und es musste eine Lösung in Software gefunden werden. Diese sollte schnell sein, durfte sich also nur aus den Operationen Plus, Minus, Division durch 2 und Multiplikation mit 2 zusammensetzen. Das ist möglich mit einem Rechenweg, der schon im Alten Ägypten vor vermutlich 5000 Jahren bekannt war.

Der Gedanke ist der folgende: a × b ist äquivalent zu 1/1 × a × b, das zu 2/2 × a × b, das ist äquivalent zu (a / 2) × (2 × b). Testen wir das:

4 × 3 = (4 / 2) × (3 × 2) = 2 × 6 = 12

Von 4 × 3 sind wir auf 2 × 6 gekommen. Und das wäre nach dem gleichen Prinzip (2 / 2) × (6 × 2) = 1 × 12 = 12. Man sieht: Wenn der Multiplikator auf 1 steht, haben steht im Multiplikand das Ergebnis. (Ein Produkt entsteht aus der Multiplikation von Faktoren. Den ersten Faktor nennt man Multiplikator, den zweiten Multiplikand.)

Ein zweites Beispiel:

MultiplikatorMultiplikand

8

7

4

14

2

28

1

56

Der Multiplikator ist bei 1 angekommen und der Multiplikand enthält mit 56 das Ergebnis.

Ein Algorithmus wäre schnell formuliert: Eine Schleife läuft so lange, wie der Multiplikator > 0 ist, teilt in Rumpf der Schleife den Multiplikator durch 2 und multipliziert den Multiplikand mit 2. Allerdings gibt es ein Problem …​

Der Multiplikator ist nicht immer eine gerade Zahl. Ist das Produkt aus 11 × 6 zu berechnen, ergibt natürlich 5,5 × 12 das gleiche Ergebnis, aber wir wollen nicht mit Fließkommazahlen arbeiten. Rechnen wir 11 × 6 wie bekannt, wird bei einer Ganzzahldivision das Ergebnis (11 / 2) × (6 × 2) = 5 × 12 = 60 sein. Das richtige Ergebnis ist 66. Es fehlen 6. Der Multiplikand ist auch 6, ist das ein Zufall?

Ungerade und gerade Zahlen liegen immer um eins auseinander. Ist a eine ungerade Zahl, so ist a - 1 eine gerade Zahl. Wollen wir a × b berechnen, dann ist das wie (a - 1 + 1) × b, und das ist ausmultipliziert (a - 1) × b + b. Ein Beispiel: 11 × 6 = (11 - 1 + 1) × 6 = (10 + 1) × 6 = 10 × 6 + 6 = 66. Das ist richtig. So könnte man weitermachen und auch 10 × 6 berechnen.

Kommen wir zurück auf den Algorithmus, der so lange den Multiplikator durch zwei teilt, bis eins erreicht ist. Sollte ein Multiplikator ungerade sein, wird der Multiplikator um eines vermindert, sodass er für den nächsten Divisionsschritt wieder gerade ist und ein „Korrekturwert“ gemerkt. Da es mehrere Korrekturen geben kann, werden diese alle summiert.

ProduktMultiplikator ungerade?Umschreibung, falls Multiplikator ungeradeKorrekturwert

22 × 3

Nein

11 × 6

Ja

(10 + 1) × 6 = 10 × 6 + 6

6

5 × 12

Ja

(4 + 1) × 12 = 4 × 12 + 12

12

2 × 24

Nein

1 × 48

Ja

(0 + 1) × 48 = 0 + 48

48

Die Summe 6 + 12 + 48 ergibt 66, und das ist 22 × 3. Verschachtelt geschrieben:

22 × 3 = 11 × 6 = (10 × 6) + 6 = ((4 × 12) + 12) + 6 = ((48) + 12) + 6 = 66.

Für die Multiplikation von beliebigen Ganzzahlen müssten nur Werte addiert, mit 2 multipliziert und durch 2 dividiert werden. Und es muss ein Test möglich sein, ob eine Zahl gerade oder ungerade ist.

Ancient Egyptian multiplication

Aufgabe:

  • Setze den Algorithmus in Java-Code um, mit und ohne Rekursion.

  • Wenn eine Addition so viel kostet wie eine Multiplikation und Division, wie lassen sich die Anzahl Durchläufe optimieren?