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:
Noch mehr Aufgaben findest du im Buch: ›Captain CiaoCiao erobert Java: Das Trainingsbuch für besseres Java. 300 Java-Workshops, Aufgaben und Übungen mit kommentierten Lösungen‹
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:
Lerne SVG an einem kleinen Beispiel unter https://tutego.de/go/trysvgcircle kennen.
Verändere auf der Webseite die Größe des Kreises.
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" );
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 bekanntenprint*(…)
-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.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
undlong
. 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
unddouble
zur Verfügung; eindouble
hat doppelt so viele Bits wie einfloat
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 zweiint
-Variablenx
,y
und einedouble
-Variabler
.Belege die Variablen mit Werten.
Baue die Belegung der Variablen in die Ausgabe ein.
Beispiel:
Ist etwa
x = 100
undy = 110
undr = 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
undr = 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:
|
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
undcy
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.
Schreibe ein Programm, was drei Fließkommazahlen mit
new java.util.Scanner(System.in).nextDouble()
erfragt und in Variablen speichert.Gibt
true
oderfalse
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
oderfalse
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:
Schreibe ein Programm, das zwei Zahlen einliest, wobei die Zahlen im Bereich von
0
bis99
(beide Grenzen inklusive) liegen sollen.Sind die Zahlen über
100
, sollen nur die letzten zwei Ziffern gewertet werden;100
oder200
wären dann wie00
(also0
),1111
wäre wie11
.Teste, ob die beiden Zahlen eine gemeinsame Ziffer haben.
Beispiele:
12
und31
haben1
als gemeinsame Ziffer.22
und33
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.
Aufgabe:
Lege eine neue Klasse
CoinMachine
an.Das Programm soll als Erstes eine Fließkommazahl für einen Geldbetrag fordern.
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 |
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)«.
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 ( |
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.
Aufgabe:
Schreibe ein Programm, das auf der Kommandozeile mit
new java.util.Scanner(System.in).nextDouble()
den Betrag der Rückzahlung einliest.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.
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 Eingabe4
0,1 und größer: Ausgabe in Zentiliter, etwa
ca. 20 cl
bei der Eingabe0,2
0,001 und größer: Ausgabe in Milliliter, etwa
ca. 9 ml
bei der Eingabe0,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 demswitch
-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
-Schleifedo
-while
-Schleifefor
-Schleifeerweiterte
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.
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.
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.
Aufgabe:
Lege eine neue Klasse
SummingCalculator
an.Nimm über den
Scanner
so lange Zahlen entgegen, bis0
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
-Variablet
zwischen0
(inklusiv) und10
(exklusiv) mit folgender Zeile:double t = Math.random() * 10;
Multipliziere
t
mit2
, wennt < 1
. Wenn jedocht >= 1
ist, ziehe1
ab.Setze diese Berechnung in eine
while
-Schleife, die enden soll, wennt
kleiner gleich0
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 |
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.
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.
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, 5987654
→ 4, 911111
→ 1, 10
→ 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.
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.
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.
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.
><> <><
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 selbstrepetitions
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:
|
|
| |
|
|
|
|
|
|
|
|
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.
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
undT
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 Typint
. Gib die Anzahl Ziffern der Zahl aus. Nutze nicht(""+n).length()
, das wäre zu einfach …
Beispiele für n
und die erwartete Ausgabe:
1234
→4
3
→1
0
→1
Integer.MAX_VALUE
→10
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.
Aufgabe:
Lege eine neue Klasse
LinePrinter
an. Setze in die Klasse eine statische Methodeline()
, die eine Linie aus zehn Herzen schreibt. Das Unicode-Zeichen "♥" kann Java in Strings speichern und ausgeben.Lege eine neue Klasse
LinePrinterDemo
an, die einemain(…)
-Methode hat undline()
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ängelen
mit Minuszeichen ("-"
) auf der Konsole ausgeben, also würdeline(3)
auf dem Bildschirm---
ausgeben.Die Methode
line(int len, char c)
soll man mit eigenen Füllzeichen aufrufen können. So gibtline(2, 'x')
die Liniexx
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!
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, andernfallsfalse
.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. |
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.
Studiere https://tutego.de/go/trysvgcircle und schreibe ein Java-Programm, das SVG auf dem Bildschirm ausgibt für genau einen Kreis.
Zeichne eine einzelne Reihe mit Kreisen.
Zeichne ein Rechteck mit Kreisen. Überlege, wie die Kreise versetzt werden.
Gib jedem Kreis zufällig einen von sechs festen Farben.
Schaue nach, wie das "Bild" eine Hintergrundfarbe bekommen kann.
Ü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:
Quantity | Flamethrower | Fire 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:
Ein paar Beispiele:
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:Listing 1. https://jsfiddle.net/Lt0djpz3/<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:
n → n/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 Methodevoid 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:
Multiplikator | Multiplikand |
---|---|
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.
Produkt | Multiplikator ungerade? | Umschreibung, falls Multiplikator ungerade | Korrekturwert |
---|---|---|---|
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.
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?
Noch mehr Aufgaben findest du im Buch: ›Captain CiaoCiao erobert Java: Das Trainingsbuch für besseres Java. 300 Java-Workshops, Aufgaben und Übungen mit kommentierten Lösungen‹