NEU
http://sites.schaltungen.at/arduino-uno-r3/processing/einstieg-in-processing/einfuehrung-in-die-programierungWels, am 2015-01-20BITTE nützen Sie doch rechts OBEN das Suchfeld [ ] [ Diese Site durchsuchen]DIN A3 oder DIN A4 quer ausdrucken ********************************************************************************** DIN A4 ausdrucken
*********************************************************
Einführung in die Programmierung mit Processing (Grafik-Spielereien)_1a.pdf Einführung in die Programmierung mit Processing 2.0 Vorbereitungen Herunterladen, installieren und starten von Processing Processing ist eine frei verfügbare Programmiersprache und -umgebung, die auf JAVA aufbaut und unter grafischen Künstlern eine grosse Fangemeinde gefunden hat. Sowohl für GNU/Linux, Mac OS X als auch für Windows stehen kostenlose Versionen zur Verfügung, die du unter www.processing.org findest. Gleichzeitig findest du unter dieser Adresse auch Einzelheiten zu den verwendeten Befehlen und weitere Informationen. Ist die passende Version installiert, so kann Processing gestartet werden.
Icon
Dreieck Quadrat Seite Pfeil nach Oben Pfeil nach unten Pfeil nach rechts Run=Startet Programm Stop=Prg. wird beendet New=Leere Seite in der IDE wird geöffnet Open=Prg wird geöffnet Save=Prg wird gespeichert Export
Programm starten
Sketch / Programm-fenster
Meldungen
Konsole / Nachrichten-Fenster Zeilen-Nummer Dein Programm wirst du in den Sketch-Bereich des Fensters schreiben. Willst du es dann laufen lassen, so klickst du oben links auf das entsprechende Symbol. Sollten syntaktische Fehler bestehen, werden diese im Meldungen-Bereich angezeigt. Ausführlichere Informationen findest du dann noch in der Konsole; hier können aber auch vom Programm aus Werte ausgegeben werden. Was ist ein Programm? Als Programm bezeichnen wir eine Folge von Befehlen, die von der Umgebung ausgeführt werden können. In den folgenden Abschnitten wirst du einige Befehle von Processing kennenlernen. Der Befehlssatz baut auf Java auf, eine der heute am meisten verwendeten Sprachen. Erweitert wurde er um etliche Befehle zur unkomplizierten Erzeugung von Grafiken. Ausgabefenster und erste Grafikbefehle Das Ausgabefenster Auch wenn du keinen einzigen Befehl geschrieben hast, kannst du dein (leeres) Programm doch schon laufen lassen. Dies funktioniert, weil Processing dir von vornherein etliches an Arbeit abnimmt. So erzeugt es automatisch ein Ausgabefenster und stellt es dar. Der Hintergrund des Ausgabefenster ist in einem hellen Grau (200) gehalten, und das Fenster ist nicht wirklich gross. Du kannst seine Grösse aber bestimmen, wenn du im Sketch-Bereich einen ersten Befehl eingibst: size(800,600); In Java (und daher auch in Processing) wird jede Anweisung durch ein Semikolon abgeschlossen. In den runden Klammern stehen zwei Werte, welche den Befehl genauer beschreiben. Solche Werte nennen wir Parameter. Der erste Parameter gibt an, wie viele Bildpunkte (Pixel) die Breite des Ausgabefensters sein soll, der zweite bestimmt die Höhe. Lässt du dein Programm nun laufen, wird ein grösseres Ausgabefenster als zuvor angezeigt; seine Breite misst die angegebenen 800 Pixel und die Höhe ist 600 Pixel gross. Sonst aber passiert immer noch nicht viel. Damit wir in diesem Fenster nun eine Grafik programmieren können, müssen wir uns ansehen, wie Punkte im Fenster beschrieben werden können. Das Koordinatensystem des Ausgabefensters
In der Mathematik wird ein kartesisches Koordinatensystem meist so gezeichnet, dass die x-Achse (die Ordinate) horizontal gelegt wird
und von links nach rechts zeigt, während die y-Achse (die Abszisse) von unten nach oben geht. Je nach Anwendung sind auf beiden Achsen auch negative Zahlen möglich. Processing weicht hier etwas ab. Der Punkt (0,0) liegt in der linken, oberen Ecke. Die x-Achse zeigt wie gewohnt nach rechts, die y-Achse aber geht nach unten. In einem Fenster, das 800 Pixel breit und 600 hoch ist, wird die x-Achse von 0 bis 800 dargestellt und die y-Achse von 0 bis 600. Der Punkt (800,600) ist so beispielsweise die rechte, untere Ecke. 0 100 200 300 400 500 600 700 800 000 0 100 200 300 400 500 600 0 Aufgabe 1 Gib in einem 800 × 600 - Fenster die folgenden Punkte an: a) rechte, obere Ecke, b) rechte, untere Ecke, c) Mitte des Fenster, d) Mitte des linken Randes, e) Mitte des rechten Randes, f) Mitte des unteren Randes. Aufgabe 2 Lies die Koordinaten der drei Punkte im 800 × 600 - Fenster heraus. Du kannst dabei davon ausgehen, dass alle Koordinaten Vielfache von 100 sind. Aufgabe 3 Es ist ein 400 × 400 - Fenster dargestellt. Bestimme die 4 Ecken des gezeichneten Quadrates, wenn du wiederum davon ausgehen kannst, dass alle Koordinaten Vielfache von 100 sind. // Processing-Sketch: Flaeche_1a.pdesize(400, 400); // Grafik-Fenster-Größerect(100, 100, 200, 200); // ergibt ein Rechteck mit linker, oberer Ecke in (x,y) und Breite b, Höhe h. Erste Zeichenbefehle Ist klar, wie die Koordinaten eines Punktes im Ausgabefenster auszulesen sind, so ist es nicht mehr schwierig, einfache Zeichnungen zu programmieren. Es stehen unter anderem die folgenden Anweisungen zur Verfügung: // Processing-Sketch: Flaechen_1a.pdesize(200, 200); // Grafik-Fenster-Größeline(0, 10, 100, 10); // zeichnet eine Linie von (x1,y1) zu (x2,y2).rect(5, 20, 50, 60); // ergibt ein Rechteck mit linker, oberer Ecke in (x,y) und Breite b, Höhe h.// zeichnet eine Ellipse mit Mittelpunkt (x,y) und Breite b, Höhe h. Für b = h ergibt sich der Spezialfall des Kreises.ellipse(100, 100, 30, 30); triangle(150, 100, 200, 150, 100, 150); // Dreieck mit Ecken in (x1,y1), (x2,y2) und (x3,y3). Mit den Befehlen ellipseMode() und rectMode() kann eingestellt werden, ob der Punkt (x,y) den Mittelpunkt oder die linke, obere Ecke bedeuten soll. Nähere Informationen findest du unter www.processing.org. Einführung in die Programmierung mit Processing Aufgabe 4 Schreibe ein Programm, welches das Bild aus Aufgabe 3 zeichnet. Aufgabe 5 Programmiere die folgende Zeichnung in einem 400 × 400 - Fenster: Aufgabe 6 Lasse Processing die folgende Zeichnung ausgeben: Aufgabe 7 Programmiere auch das Folgende, wobei der Kreis einen Durchmesser von 350 Punkten hat. Wie musst du das Programm ändern, damit das Produkt so aussieht? Vektor- und Pixelgrafiken Es gibt zwei recht unterschiedliche Arten, um Bilder und Grafiken zu speichern. In einer Pixelgrafik wird in einem rechteckig angelegten Punkteraster für jeden Punkt die Farbe abgelegt. Wird ein solches Bild dann vergrössert, müssen diese Punkte grösser angezeigt werden, was bei zu niedrigen Auflösungen schnell zu einem "Klötzchenbild" führt. Ist die Punktedichte aber hoch genug, kann das Bild scharf wie eine Fotografie sein; nicht zuletzt in digitalen Kameras werden solche Pixelgrafiken auch erzeugt. (Die Bildauflösung kommt dort von der Auflösung des Bildsensors.) Typische Bildformate für Pixelbilder sind *.GIF, *.JPEG oder auch *.TIFF. Ein anderer Weg wird bei Vektorgrafiken eingeschlagen. Hier wird das ganze Bild durch Punkte, Linien und Flächen aufgebaut, die in einem Koordinatensystem beschrieben werden. Diese Linien können verschiedene Ausprägungen haben (zum Beispiel verschieden dick, ausgezogen, gestrichelt oder gepunktet sein), ebenso die Flächen. Wird ein solches Vektorbild vergrössert, bleibt die Grafik sauber, sie verpixelt also nicht. Der Nachteil ist aber, dass solche Vektorbilder nicht einfach fotografiert oder eingescannt werden können, sondern in meist mühevoller Arbeit erstellt werden müssen. Typische Bildformate für Vektorgrafiken (die natürlich auch Text enthalten können) sind EPS und PDF. In Processing arbeiten wir in einem Koordinatensystem und erzeugen also eine Vektorgrafik. Die Ausgabe der Grafik auf dem Bildschirm verpixelt das Bild zwar notgedrungen (das Bild eines Monitors ist immer aus einzelnen Punkten aufgebaut ist), wir können die Grafik aber auch als pdf-Datei speichern und dann mit einem geeigneten Programm (beispielsweise dem freien Acrobat Reader von Adobe) ansehen und beliebig vergrössern. Um eine Grafik zusätzlich zur Bildschirmausgabe auch als pdf-Datei zu bekommen, müssen wir einige zusätzliche Zeilen in unser Programm einfügen: • Als erstes muss die pdf-Bibliothek eingebunden werden: import processing.pdf.*; • Nach(!) dem size()-Befehl beginnen wir dann damit, zusätzlich zur Ausgabe im Fenster auch in eine Datei zu schreiben: beginRecord(PDF, "Grafik.pdf"); (statt "Grafik.pdf " kann auch ein anderer Name gewählt werden.) • Ist die Grafik fertig, schliesst der Befehl endRecord(); die Ausgabe in die pdf-Datei ab. Sie wird im Sketch-Ordner abgelegt. Beispiel Stern // Processing-Sketch: Stern_1a.pdeimport processing.pdf.*; // bindet die pdf-Bibliothek einsize(400, 400); // Legt die Grösse festbeginRecord(PDF, "Grafik.pdf"); // Beginn des Schreibens in die pdf-Dateiline(30, 120, 170, 170);line(170, 170, 190, 20);line(190, 20, 230, 165);line(230, 165, 360, 125);line(360, 125, 250, 230);line(250, 230, 350, 370);line(350, 370, 210, 265);line(210, 265, 90, 380);line(90, 380, 160, 230);line(160, 230, 30, 120);endRecord(); // Ende des Schreibens in die pdf-Dateiund Breite b, Höhe h Hinweise: • Wenn du die Grafik im Ausgabefenster mit derjenigen im pdf-Dokument vergleichst, wirst du feststellen, dass der Hintergrund verschieden ist. Im Ausgabefenster ist er grau, im pdf-Dokument hingegen weiss. • Im obigen Beispiel haben wir Kommentare verwendet. Sie beginnen mit den Zeichen "//", die Processing anweisen, den Rest der Zeile nicht zu beachten. Kommentare erhöhen damit die Lesbarkeit eines Programms für den Menschen, ohne dass sie eine Auswirkung auf das Programm selbst haben. Soll ein Text über mehrere Zeilen als Kommentar gekennzeichnet werden, wird er zwischen die Zeichenkombinationen "/*" (als Beginn) und "*/" (als Ende) gesetzt, beispielsweise /* Beispiel eines Programms, das die Ausgabe zusätzlich zur Bildschirmausgabe auch in eine Datei speichert */ import processing.pdf.*; // bindet die pdf-Bibliothek ein size(400,400); // Legt die Grösse fest ... Linien- und Flächenattribute in Processing Da eine Vektorgrafik durch Linien und Flächen aufgebaut ist, sollte es möglich sein, das Aussehen der Linien (die als Umrandung auch bei Flächen auftreten) und das der Flächeninhalte zu verändern. Neben der Farbgebung, die wir im nächsten Abschnitt ansehen werden, stellt Processing die folgenden Befehle zur Verfügung. Und so, wie ein Künstler zuerst den Pinsel und die Farbe wählt und dann malt, müssen auch beim Programmieren die Attribute vor dem Zeichnen gesetzt werden. Attribute der Linien Linienbreite strokeWeight(x); setzt die Liniendicke auf eine Breite von x Pixel. Beispiel Linienbreite // Processing-Sketch: LinienBreite_1a.pdesize(400, 400);strokeWeight(0.5);line(50, 50, 350, 50);strokeWeight(1);line(50, 100, 350, 100);strokeWeight(2.5);line(50, 150, 350, 150);strokeWeight(5);line(50, 200, 350, 200);strokeWeight(10);line(50, 250, 350, 250);strokeWeight(25);line(50, 300, 350, 300);strokeWeight(50);line(50, 350, 350, 350); Verbindung zweier Strecken (die zum gleichen Streckenzug gehören) strokeJoin(Modus); Werden zwei Strecken zusammengeschlossen, so kann das Aussehen der Ecke mit strokeJoin(Modus) festgelegt werden. Mit strokeJoin(MITER) werden die langen Aussenkanten der Linie bis zum Schnittpunkt weitergeführt, es entsteht (vor allem bei kleinen Winkel) eine lange Spitze. Bei strokeJoin(BEVEL) werden die Aussenkanten der Linien direkt miteinander verbunden, die Spitze erscheint abgeschnitten. strokeJoin(ROUND) schliesslich führt dazu, dass die Aussenkanten über einen Kreis miteinander verbunden werden und eine abgerundete Ecke entsteht. Beispiel Aussehen der Ecke // Processing-Sketch: Aussehen der Ecke_1a.pdesize(400, 400);strokeWeight(25);strokeJoin(MITER);rect(50, 50, 300, 300);strokeJoin(BEVEL);rect(90, 90, 220, 220);strokeJoin(ROUND);rect(130, 130, 140, 140); Linienenden strokeCap(Modus); Die Enden einer Linie können ebenfalls verschieden sein. Mit strokeCap(ROUND) wird mit einem Halbkreis abgeschlossen. strokeCap(SQUARE) bewirkt, dass die Halbkreise vollständig fehlen, währenddem strokeCAP(PROJECT) dazu führt, dass statt Halbkreise Quadrate angehängt werden (die Linie wird dann an jedem Ende um ihre Dicke länger). Beispiel Linienenden // Processing-Sketch: Aussehen der Linienenden_1a.pdesize(400, 200);strokeWeight(20);strokeCap(ROUND);line(50, 50, 350, 50);strokeCap(SQUARE);line(50, 100, 350, 100);strokeCap(PROJECT);line(50, 150, 350, 150); Attribute der Flächen Flächen bestehen aus Begrenzungslinien und Flächeninhalt. Die Begrenzungslinien werden wie oben erklärt mit strokeWeight(), strokeJoin() und strokeCap() formatiert. Sollen sie gar nicht gezeichnet werden, so kann vor dem Zeichnen der Fläche der Befehl noStroke() verwendet werden. Ist zwar die Begrenzungslinie aber keinen Inhalt gewünscht, hilft der Befehl noFill(). noStroke() Zeichnet eine Fläche ohne Begrenzungslinie. noFill() Zeichnet keinen Flächeninhalt. (Beachte bei beiden Befehlen die notwendige Klammer ohne Inhalt.) Beispiel Flächenattribute // Processing-Sketch: Flaechen Attribute_1a.pdesize(400, 200);background(200);ellipse(100, 100, 120, 80);noFill();ellipse(300, 100, 120, 80); Aufgabe 8 Programmiere die folgende Grafik , welche in einem 800 × 200 - Fenster vier Kreise mit einem Radius von 90 Punkten darstellt. Die Liniendicken sind (ganz links) 20 Punkte, dann 5 Punkte,1 Punkt und zuletzt soll gar keinen Linie mehr gezeichnet werden. Aufgabe 9 Lasse dir in einem 800 × 200 - Fenster die nebenstehend gezeigten Kreise zeichnen. Die Mittelpunkte liegen in (100,100), (200,100), ... , (700,100) und die Radien betragen jeweils 65 Pixel. Farben Farbmodelle In der Natur gibt es eine ganze Reihe reiner Farben: Du kannst sie beispielsweise sehen, wenn du einen Regenbogen betrachtest: sein Farbspektrum erstreckt sich von Rot über Orange, Gelb, etlichen Grüntönen bis Türkis, Blau und Violett. Dabei wurden nur einige Farben benannt, und auch diese sehr ungenau. Jenseits der Farben am Rand des Regenbogens gibt es noch weitere, die wir aber nicht sehen können. Alle die (sichtbaren) Regenbogenfarben könnten unterschieden werden, da sie zu je einer Wellenlänge des Lichts gehören. Unser Auge ist, was die Wahrnehmung der Farben angeht, allerdings nicht so sensitiv. Für die Farbwahrnehmung haben wir nur drei verschiedene Typen von Farbzäpfchen: ein Typ reagiert auf ungefähr rotes Licht, ein zweiter auf grüne Farbtöne und ein dritter auf blaues Licht verschiedener Farbtöne. Werden nun beispielsweise sowohl rote als auch grüne Farbzäpfchen etwa gleich stark angeregt, schliessen wir im Hirn daraus, dass es sich um die Farbe handeln muss, die im Regenbogen zwischen diesen beiden liegt, und registrieren die Farbe Gelb. Dies auch dann, wenn überhaupt kein gelbes Licht vorhanden ist, sondern gleichzeitig rotes als auch grünes Licht ins Auge fällt. Für unser Farbsehen von einfallendem Licht genügen daher die drei Grundfarben Rot, Grün und Blau; die restlichen Farben können daraus gemischt werden. Die Farbmischung ist aber alles andere als unproblematisch. So können Farben auf zwei ganz unterschiedliche Arten entstehen. Wir sehen sie uns im Folgenden an: Additive Farbmischung (Lichtmischung, RGB-Farbmodell) Wir können Mischfarben als Überlagerung verschiedenfarbigen Lichts erzeugen. Da wir Farbzäpfchen für Rot, Grün und Blau haben, nehmen wir diese Farben als Grundfarben. Alle anderen Farben werden daraus aufgebaut, und das Farbmodell wird entsprechend RGB-Modell genannt. Wird hier beispielsweise sowohl Rotes, als auch Grünes und Blaues Licht gemischt, so entsteht Weiss. Schwarz umgekehrt erreichen wir, indem weder Rotes, noch Grünes, noch Blaues Licht vorhanden ist. yellow erhalten wir bei etwa gleich starkem Rot- als auch Grünanteil und ohne Blau. Eine solche Lichtmischung liegt vor, wenn wir das Bild eines Monitors oder eines Beamers betrachten. Subtraktive Farbmischung (Mischung von Deckfarben, CMY-Farbmodell) Anders sieht es aus, wenn Deckfarben auf einem weissen Untergrund gemischt werden. Mischen wir zwei Deckfarben, so kommt nicht mehr sondern weniger verschiedenes Licht ins Auge, denn die Deckfarben absorbieren Licht aus der (weissen) Lichtquelle. Ist keine Deckfarbe vorhanden, sehen wir den weissen Untergrund, wird alles gemischt, so entsteht ein (schmutziges) Schwarz. Wir haben daher die exakt umgekehrte Situation des RGB-Modells. Um wieder auf die Farben der Farbzäpfchen zu kommen, nehmen wir als Grundfarben jeweils weisses Licht, dem eine der Farben Rot, Grün und Gelb fehlt. Fehlt rotes Licht, so haben wir nur grünes und blaues Licht, also die Lichtmischfarbe cyan. Fehlt grünes Licht, so sehen wir einen Lila-Ton, der als magenta bezeichnet wird. Bei fehlendem blauen Licht entsteht yellow. Diese drei Farben cyan, magenta und yellow sind die Grundfarben des CMY-Farbmodells. Häufig wird als vierte Farbe noch ein tiefes Schwarz dazugenommen wird, um nicht mit dem etwas schmutzigen Schwarz leben zu müssen, wir reden dann vom CMYK-Modell (das K steht für "Black"). Es kommt dort zur Anwendung, wo Deckfarben gemischt werden, beispielsweise bei der Ausgabe über einen Farbdrucker. Aufgabe 10 Die folgenden Diagramme zeigen nochmals die additive und die subtraktive Farbmischung, allerdings sind die Felder alle leer gelassen. Schreibe in alle Felder die Namen der Farben, die dort hinein gehören. RGB-Modell CMY-Modell Farben mit Processing In Processing wird sowohl das RGB- als auch das CMYK-Farbmodell unterstützt, wobei das RGB-Modell die Standardeinstellung ist. Wir werden uns im Folgenden auch nur damit auseinandersetzen. Farben werden durch drei Werte zwischen 0 und 255 angegeben; der erste Wert bestimmt den Rot-Anteil, der zweite den Grün- und der dritte den Blau-Anteil. 0 bedeutet dabei, dass die entsprechende Farbe gar nicht vorkommt, 255 ist das Maximum vom entsprechenden Farbanteil. Drei Befehle setzen (vor dem Zeichnen) die Farbe: background(r,g,b); übermalt das ganze Bild mit der Farbe, die den Rotanteil r, Grünanteil g und Blauanteil b hat. stroke(r,g,b); setzt die Linienfarbe mit Rotanteil r, Grünanteil g und Blauanteil b. fill(r,g,b); legt die Flächenfarbe fest, wiederum mit Rotanteil r, Grünanteil g und Blauanteil b. Beispiel Orange bis GelbGrün // Processing-Sketch: Orange bis GelbGruen_1a.pdesize(400, 200);background(50, 0, 55);noStroke();fill(250, 180, 0); // Orangerect(20, 70, 60, 60);fill(230, 200, 0); // warmes Gelbrect(120, 70, 60, 60);fill(210, 220, 0); // grünliches Gelbrect(220, 70, 60, 60);fill(190, 240, 0); // Gelbgrünrect(320, 70, 60, 60);strokeWeight(15);strokeCap(SQUARE);stroke(255, 255, 255);line(20, 40, 380, 40);line(20, 160, 380, 160); Aufgabe 11 Zeichne in einem 600 × 200 - Fenster 6 Rechtecke mit Flächenfarben Rot, Gelb, Grün, Cyan, Blau und Magenta. Aufgabe 12 In einem Fenster von 400 Pixel Breite und 200 Pixel Höhe soll die folgende Grafik erscheinen, in welcher Quadrate mit den Rottönen (240,0,0), (180,0,0), (120,0,0) und (60,0,0) sowie darunter mit Grüntönen (0,60,0), (0,120,0), (0,180,0), (0,240,0) angezeigt werden. Aufgabe 13 Ändere obiges Programm so ab, dass es eine neue Farbkombination darstellt. Wenn du die RGB-Werte einer bestimmten Farbe suchst, kann dir der "Color Selector" helfen, den du im Menu unter Tools findest. Aufgabe 14 Bestimme RGB-Werte für Gelbgrün, Rosarot, Violett, Braun und für ein mittleres Grau. Festlegen von Grautönen Sind die Rot-, Grün- und Blauanteile alle gleich, so entsteht ein Grau. Processing erlaubt es, statt aller drei Werte nur einen anzugeben, so ist beispielsweise fill(205) das Gleiche wie fill(205,205,205). Aufgabe 15 Verwende ausschliesslich Farbangaben mit nur einem Parameter, um die nebenstehende Grafik von 400 × 400 Pixel Grösse zu erzeugen. Aufgabe 16 Eine bekannte optische Täuschung ist die folgende Zeichnung, in der beide Kreise den gleichen Grauton haben, wegen des unterschiedlich hellen Hintergrunds aber verschieden wirken. Schreibe ein kleines Programm, welches ein solches Bild zeichnet. Die Undurchsichtigkeit Wird bei Grautönen noch ein zweiter oder bei RGB-Farben noch ein vierter Parameter mit einem Wert zwischen 0 und 255 angegeben, so bedeutet dieser die Undurchsichtigkeit der Farbe; fill(128,10) füllt beispielsweise mit einem fast durchsichtigen, mittleren Grauton, fill(240,190,10,200) führt zu einem goldenen Farbton, durch welchen der Untergrund nur noch wenig sichtbar ist. fill(240,190,10,255) ist dann das Gleiche wie fill(240,190,10), da die Farbe maximal abdeckt. Aufgabe 17 Programmiere die folgende Grafik: Variablen Grundlegendes Variablen sind Speicherplätze mit Namen, in die geschrieben und aus denen auch wieder gelesen werden kann. Um einen solchen Speicherplatz in einem Programm verwenden zu können, muss • festgelegt werden, welchen Inhalt der Speicherplatz aufnehmen wird. Wir werden vorerst nur zwei Arten betrachten, nämlich Ganzzahlen ("integer", kurz int) und Fliesskommazahlen ("floating point", kurz float). • ein Name vergeben werden. Dieser kann beliebig lang sein, muss aber mit einem Buchstaben, dem Dollarzeichen "$" oder einem Underscore "_" beginnen. Es wird dabei zwischen Gross- und Kleinbuchstaben unterschieden. Beides geschieht über Anweisungen wie beispielsweise int zahl; deklariert eine Variable mit Namen zahl, die einen ganzzahligen Wert (integer) aufnehmen kann. float d; erzeugt eine Variable mit Namen d, welche einen Fliesskommawert (floating point) speichern kann. Ist eine Variable einmal deklariert, so kann ihr ein neuer Wert zugewiesen werden. Dies geschieht mit dem Gleichheitszeichen: a = 64; weisst der Variablen a den Wert 64 zu. Das Gleichheitszeichen ist hier ein Zuordnungszeichen; der Variablename muss auf der linken Seite stehen, der zuzuordnende Wert auf der rechten. Deklarierung und Wertzuweisung können auch zusammengenommen werden, so ist int a; … a = 64; das Gleiche wie int a = 64; Die Variable muss nur einmal deklariert werden; Werte können ihr danach immer wieder zugewiesen werden. Beispiel: int a = 3; a = 5; … a = 3*4*4; Wird eine Variable vom Typ int oder float zwar deklariert, ihr aber kein Wert zugewiesen, so hat sie den Wert 0. Natürlich kann einer Ganzzahl-Variablen kein nicht-ganzer Zahlenwert zugewiesen werden (dafür ist der Speicherplatz nicht vorgesehen). Umgekehrt sind Fliesskommazahlen oft leicht gerundet, da die Anzahl Stellen beschränkt ist. Aufgabe 18 Welche Deklarierungen und Wertzuweisungen sind gut, welche nicht? a) int zahl = 25; b) int zahl = 25.5; c) float zahl = 25.5; d) int wert = -25; e) int wert = -25.5; f) float wert = -25.5; g) int ?wert = 3; h) int $wert = 3; i) int _wert = 3; j) int *wert = 3; k) 3 = int wert; Aufgabe 19 Welche der folgenden Anweisungen funktionieren, welche nicht? Probiere aus und erkläre. a) int a = 5.2; b) int a = -2004; c) float a = 5.2; d) float a = -2004; Aufgabe 20 Die folgenden beiden Programme zeichnen das Gleiche: // Processing-Sketch: 4Kreise1_1a.pdeint r = 65; // Radius der Kreiseint ab = 20; // Abstand zum Randsize(8*r+2*ab, 2*r+2*ab);background(10, 80, 120);noStroke();fill(200, 130, 0);ellipse(ab+r, ab+r, 2*r, 2*r);ellipse(ab+3*r, ab+r, 2*r, 2*r);ellipse(ab+5*r, ab+r, 2*r, 2*r);ellipse(ab+7*r, ab+r, 2*r, 2*r); und // Processing-Sketch: 4Kreise2_1a.pdesize(560, 170);background(10, 80, 120);noStroke();fill(200, 130, 0);ellipse(85, 85, 130, 130);ellipse(215, 85, 130, 130);ellipse(345, 85, 130, 130);ellipse(475, 85, 130, 130); Das Programm soll nun so abgeändert werden, dass die Kreise statt eines Radius von 65 Pixel nun einen mit 82 Pixel Grösse haben. (Natürlich sollen immer noch alle 4 Kreise voll sichtbar sein.) Welches Programm kann schneller abgeändert werden? Aufgabe 21 Erweitere das Programm, so dass im Ausgabefenster direkt aneinander angrenzend vier Quadrate mit den Grundfarben Rot, Grün, Blau und Weiss angezeigt werden. Verwende dabei nur Rechnungen mit Variablen, keine ausgerechneten Werte. // Processing-Sketch: 4FarbFenster_1a.pdeint groesse = 150; // Grösse eines Quadratesint n = 0; // n(ichts) - kein entsprechender Farbanteilint v = 255; // v(iel) - grösstmöglicher Farbanteilsize(4*groesse, groesse);fill(v, n, n);rect(0, 0, groesse, groesse);fill(n, v, n);rect(groesse, 0, groesse, groesse);//fill(n, n, v);//rect(groesse*2, 0, groesse, groesse);//fill(v, v, v);//rect(groesse*3, 0, groesse, groesse); Rechnen mit Variablen Wenn mit Variablen gerechnet wird, muss unterschieden werden, um welchen Typ es sich handelt, denn die Rechenoperationen sind teilweise verschieden. Operationen mit Fliesskommazahlen (float) Hier sind die Grundoperationen so, wie sie aus der Schulmathematik bekannt sind. (In den folgenden Beispiele nehmen wir an, dass a den Wert 11.0 habe.) Addition c = a + 2; c erhält den Wert 13. Subtraktion c = a - 14.5; c erhält den Wert -3.5. Multiplikation c = a * 3.5; c erhält den Wert 38.5. Division c = a / 2.5; c erhält den Wert 4.4. Operationen mit Ganzzahlen (int) Hier sind sowohl die Operanden als auch das Ergebnis ganzzahlig. Dies wirkt sich speziell auf Division aus. (Wir nehmen wieder an, dass a den Wert 11 - nun als Ganzzahl - habe.) Addition c = a + 2; c erhält den Wert 13. Subtraktion c = a - 14; c erhält den Wert -3. Multiplikation c = a * 3; c erhält den Wert 33. Ganzzahldivision c = a / 4; c erhält den Wert 2. (Der Rest wird weggelassen) Rest der Division c = a % 4; c erhält den Wert 3. Dies ist der Rest der Division a / 4. Aufgabe 22 Bestimme den Wert der Variable x int b; int x; a) b = 4; x = 3 * b; b) b = -5; x = 2 - b; c) b = 4; x = b * b * b; d) b = 7; x = b / 2; e) b = 7; x = b % 2; float b; float x; f) b = 4.2; x = 3 * b; g) b = -5.2; x = 2 - b; h) b = 4; x = b * b * b; i) b = 7; x = b / 2; Die Ganzzahldivision kann einige Probleme schaffen. Sehen wir uns den folgenden Code an: float a; a = 1 / 3 * 25.3; Wird nun a ausgegeben, folgt die Überraschung: a hat den Wert 0! Zum Verständnis müssen wir uns ansehen, wie eine Wertzuweisung behandelt wird. Als Erstes wird der Wert der rechten Seite von links her beginnend berechnet. Dazu wird 1 durch 3 geteilt, und dies gibt, weil sowohl 1 als auch 3 Ganzzahlen sind, 0. Als Nächstes wird dann 0 * 25.3 gerechnet und dieser Wert, der wiederum 0 ist, der Variablen a zugewiesen. Das Problem kann umgangen werden, indem statt 1 / 3 der Ausdruck 1. / 3 geschrieben wird, denn der Dezimalpunkt führt dazu, dass 1. als Fliesskommazahl angesehen und also mit der Fliesskommazahl-Division gerechnet wird. Ausgabe der Werte einer Variable Es ist oft hilfreich, während des Programmablaufs sich den Wert einer Variable ausgeben zu lassen. Dies geschieht mittels println(a); gibt den Wert der Variable a in der Konsole aus Es ist dabei auch möglich, zusätzlichen Text anzufügen, dieser wird dann in Anführungs- und Schlusszeichen gestellt und mit "+" verknüpft. Beispiel: println("Der Wert von a beträgt "+a); Aufgabe 23 Was gibt das folgende Programm aus? int a = 6; int b; b = a * (a-1); println("b = " +b); Aufgabe 24 Welcher Wert wird im folgenden Fall ausgeben? Überlege dir das Ergebnis zuerst und überprüfe danach, indem du das Programm laufen lässt. int a = 3; int b = 5; int c; c = b / a + a / b; println("c hat nun den Wert "+c); Von Bits und Bytes und Typen Computer speichern und rechnen im Binärsystem, in welchem eine Stelle entweder eine 0 oder eine 1 ist. Eine solche Stelle wird dabei Bit genannt. Mit acht Stellen lassen sich so 28 = 256 verschiedene Kombinationen erreichen: 00000000, 00000001, 00000010, 00000011, 00000100, ..., 11111111 Damit der Computer mit Daten umgehen kann, genügt die Bitfolge alleine jedoch nicht. Um sie richtig interpretieren zu können, muss er zusätzlich wissen, um welchen Datentyp es sich handelt. Ist es eine natürliche Zahl, so kann der Wert (beispielsweise 001001112) direkt in das Zehnersystem umgewandelt werden: 001001112 = 0·27+0·26+1·25+0·24+0·23+1·22+1·21+1·20 = 32+4+2+1 = 39 Handelt es sich aber um einen Datentyp, mit welchem auch negative Zahlen gespeichert werden können, kann es nicht einfach diese Umrechnung sein, denn so würden nie negative Zahlen entstehen – ganze Zahlen müssen also anders kodiert werden. Geht es aber um ein Zeichen (der Tastatur), so braucht es eine Tabelle, in welcher nachgesehen werden kann, welcher Wert zu welchem Zeichen gehört. Es ist also klar, dass es verschiedene Datentypen geben muss; die beiden Datentypen int und float haben wir bereits kennengelernt. Als die ersten Computer aufkamen, war man der Meinung, dass mit 28 = 256 verschiedenen Zeichen alle Ziffern, Buchstaben und Sonderzeichen kodiert werden könnten, weshalb 8 Bits zu einem Byte zusammengefasst wurden. (Heute weiss man, dass 256 Zeichen bei weitem nicht genug sind, es gibt viel zu viele Sprachen mit speziellen Buchstaben.) Wir haben also: das bit kann 2 Zustände speichern (0 oder 1) das Byte besteht aus 8 Bit und kann daher 28 = 256 Zustände speichern (00000000 bis 11111111) Sowohl für den Datentyp int als auch für float werden 32 Bits, also 4 Bytes verwendet. Es ist unmöglich, mit 32 (binären) Stellen alle Zahlen genau angeben zu können. Daraus entstehen einige Besonderheiten, die im Hinterkopf behalten werden müssen. Der Datentyp float Der Datentyp float speichert Fliesskommazahlen und braucht einen Teil des Platzes für Nachkommastellen. Da er nicht nur ganze Zahlenwerte speichern kann, ist er recht universell einsetzbar, aber manchmal auch ungenau, wie das folgende Beispiel zeigt: float a = 123456789; float b = 123456795; float c = b - a; println(c); Obwohl die beiden Zahlen a und b eine Differenz von 6 haben, wird eine Differenz von 0.0 ausgegeben; a und b werden also als gleiche Bitfolge abgespeichert. Rechnen wir das Quadrat von a aus und lassen es ausgeben println(a * a); so ist noch alles in Ordnung: Interessant wird aber die Ausgabe println(a*a*a*a*a); Sie führt auf Infinity (oder auf Deutsch: Unendlich) – die Zahl ist zu gross, als dass sie noch gespeichert werden könnte. Der Datentyp int Da der Datentyp int keine Nachkommastellen speichern muss, kann er grössere Zahlen exakt speichern. Nehmen wir das gleiche Beispiel wie für float, nun aber mit dem Datentyp int, so erhalten wir int a = 123456789; int b = 123456795; int c = b - a; println(c); die (richtige) Ausgabe 6. Rechnen wir nun aber println(a * a) So erhalten wir -1757895751, was definitiv falsch ist, da das Quadrat von a sicher nicht negativ ist. Der Grund für diesen Wert ist, dass das Resultat zu gross ist, und während bei float noch der Hinweis Infinity ausgegeben wird, entsteht hier einfach eine negative Zahl. (Wieso das so ist, weder wir uns bald ansehen.) Zusammengefasst können wir festhalten: • Der Datentyp float ist universeller, da er auch für Zahlen mit Nachkommastellen geeignet ist und grössere Zahlen aufnehmen kann. Nachteilig ist, dass die interne Darstellung meist nicht exakt ist, und sich so Ungenauigkeiten einschleichen können. • Der Datentyp int speichert hingegen nur Ganzzahlen. Liegen diese im erlaubten Bereich (von -2‘147‘483‘648 bis 2‘147‘483‘647), so werden die Zahlen exakt gespeichert. Ist die Zahl allerdings grösser oder kleiner, entsteht (meist) ein komplett falsches Resultat. Der Datentyp byte als Beispiel für int Um den Datentyp int besser zu verstehen, betrachten wir seinen kleineren Bruder, den Datentyp byte, der (wie sein Name schon sagt) einen Platz von nur einem Byte, also 8 binären Stellen hat. Der Datentyp byte kann Zahlen zwischen -128 und 127 darstellen. Für die positiven Zahlen ist seine Darstellung einfach die Schreibweise im Zweiersystem: 104 = 011010002 oder 29 = 000111012 Die grösste Zahl, 127, ist 011111112, alle positiven Zahlen beginnen also mit einer führenden Null. Die Zahl 0 ist 000000002, hat also auch eine führende Null. Negative Zahlen werden nun durch eine führende 1 dargestellt, und zwar mit derjenigen Darstellung, welche die um 256 erhöhte Zahl hätte. So hat -93 also die Darstellung von -93+256 = 149, also 100101012. Die kleinste Zahl ist -128 mit der Darstellung von -128+256=128 = 100000002. Zählen wir von der kleinsten Zahl nach oben, erhalten wir binär 100000002 100000012 100000102 100000112 100001002 ... 111111112 dezimal -128 -127 -126 -125 -124 ... -1 binär 000000002 000000012 000000102 000000112 000001002 ... 011111112 dezimal 0 1 2 3 4 ... 127 Addieren wir zu 127 noch 1, so entsteht die Zahl 100000002, die statt 128 nun eben -128 entspricht, und dies ohne Fehlermeldung. Dies ist der Grund, weshalb beim Datentyp byte, aber auch bei int, eine total falsche Zahl entstehen kann, wenn das Resultat zu gross oder zu klein ist . Sonst aber ist die oben skizzierte Darstellung sehr angenehm, denn die Addition und die Subtraktion von Zahlen in Format byte geht so, wie wir es von der schriftlichen Rechnung her kennen. Wollen wir beispielsweise 79 - 14 rechnen, so schreiben wir die Subtraktion von 14 als Addition mit -14, und rechnen 79 + (-14). 79 ist binär 010011112, -14 hat die Darstellung von -14 + 256 = 242, also 111100102. Damit erhalten wir 0 1 0 0 1 1 1 1 + 1 1 1 1 0 0 1 0 1 0 1 0 0 0 0 0 1 Die vorderste 1 hat keinen Platz, da ein Byte fest nur 8 Stellen aufnehmen kann. (Die vorderste 1 entspricht den 256, die wir zu -14 addiert haben, um auf die binäre Darstellung zu kommen.) Das Resultat ist nun 010000012 = 65. Aufgabe 25 Berechne ebenso 77-38. Aufgabe 26 Was gibt es, wenn (mit Datentyp byte) der Wert 92 zu 57 addiert wird? Kilo-, Mega, Giga- und Terabytes Ist eine Einheit definiert, so können nach dem SI-Standard neue Einheiten durch Vorstellen eines Präfixes daraus generiert werden. So ist 1 kg = 1000 g, und ein 1 km = 1000 m. 1 MW (Megawatt) sind 1000 kW (Kilowatt) und also 1'000'000 W (Watt). Gleiches geht auch für das Byte: 1 kB (Kilobyte) = 1000 B (Byte) 1 MB (Megabyte) = 1000 kB 1 GB (Gigabyte) = 1000 MB 1 TB (Terabyte) = 1000 GB. Leider hat sich neben der 1000-Einteilung auch noch eine 210 = 1024-Einteilung etabliert. Dies führt dazu, dass eine Festplatte, die vom Hersteller mit 2 GB = 2·1000·1000·1000 B angeschrieben wird, unter Windows nur mit 1.86 GiB = 1.86·1024·1024·1024 B angezeigt wird. Die Einheit GiB heisst eigentlich Gibibyte, wird aber oft auch Gigabyte genannt und mit GB abgekürzt. Neben Gibibyte gibt es noch da Mebibyte (MiB) und das Kibibyte (kiB). Werden die "bi"-s nicht geschrieben, kann es einige Unklarheiten geben. Iterationen: Die while-Schleife Wir haben bisher ein Programm stets im Code angegeben, den Processing direkt umsetzen kann. Manchmal möchte man eine Idee aber auch etwas unabhängiger von der verwendeten Programmiersprache hinschreiben; in einem solchen Fall bietet es sich an, die Befehle etwas umgangssprachlich anzugeben, beispielweise als mache ein Quadrat der Seitenlänge 20, beginnend in (10,85). Ein solcher Code wird Pseudocode genannt. Er sollte klar und detailliert genug geschrieben sein, dass die Übersetzung in eine gängige Programmiersprache problemlos möglich ist. Sehen wir uns nun in Pseudocode die folgenden Anweisungen an: mache ein Quadrat der Seitenlänge 20, beginnend in (10,85) mache ein Quadrat der Seitenlänge 20, beginnend in (40,85) mache ein Quadrat der Seitenlänge 20, beginnend in (70,85) mache ein Quadrat der Seitenlänge 20, beginnend in (100,85) mache ein Quadrat der Seitenlänge 20, beginnend in (130,85) … mache ein Quadrat der Seitenlänge 20, beginnend in (370,85) Es ist unbestritten kürzer, es so auszudrücken: beginne bei x = 10 solange x < 400 ist: mache zuerst ein Quadrat der Seitenlänge 20 bei (x,85) und erhöhe dann x um 30. Als Nassi-Shneidermann-Diagramm dargestellt sieht dies so aus: x = 10 solange x < 400 mache ein Quadrat der Seitenlänge 20 bei (x,85) erhöhe x um 30 Wir sehen darin eine Iteration, also eine Wiederholung, die durch den logischen Ausdruck x < 400 kontrolliert wird; solange der Ausdruck wahr ist, wird der ihm folgende Block von Anweisungen ausgeführt. Die Umsetzung in Processing ist: // Processing-Sketch: while-Schleife_1a.pdeint x = 10;size(400, 100); // Grösse des Ausgabefensterswhile (x<400) { rect(x, height/2, 20, 20); x = x + 30;} Die Schleife wird über das Schlüsselwort while erzeugt, gefolgt von einer Bedingung, die angibt, wie lange die Schleife abgearbeitet werden soll. Es wird jeweils diejenige Anweisung wiederholt, die nach der while-Befehl steht. Sollen es mehrere Anweisungen sein, müssen diese mittels der geschweiften Klammern "{" und "}" zu einem Block zusammengefasst werden; es wird dann also alles wiederholt, was zwischen diesen Klammern steht. Damit die Schleife einmal abbricht, muss der x-Wert während des Durchgangs des zu wiederholenden Blocks geändert werden. Die Anweisung x = x + 30; sieht eigenartig aus, wenn sie als Gleichung interpretiert wird. Du weisst aber, dass es sich hier um eine Wertzuweisung handelt: zuerst wird die rechte Seite berechnet (also zum Wert von x noch 30 addiert) und dann dieses Resultat in die Variable x geschrieben. In Anlehnung an das Nassi-Shneidermann-Diagramm wird der zu wiederholende Block links eingerückt. Dies hilft, die Struktur des Programms schnell zu überblicken. Für Processing selbst hat das Einrücken keinerlei Bedeutung und könnte auch weggelassen werden. Aufgabe 27 Ändere oberes Programm so ab, dass es in einem 800 × 200 - Fenster bis zum rechten Rand hin Quadrate zeichnet. Aufgabe 28 Was passiert, wenn die Zeile x = x + 30; weggelassen wird? Aufgabe 29 Programmiere die nebenstehende Grafik. Sie ist 400 × 400 Punkte gross und beinhaltet lauter horizontal gezeichnete Strecken, die zum Nachbarn jeweils eine Distanz von 10 Pixel haben. Aufgabe 30 Erweitere das Programm, so dass die nebenstehend gezeigte Grafik erzeugt wird. Aufgabe 31 Schreibe ein Progamm, das in einem 400 × 400 Punkte grossem Fenster die nebenstehende Grafik zeigt. Die Enden benachbarter Linien sind jeweils 10 Punkte voneinander entfernt. Aufgabe 32 Baue das letzte Programm wie nebenstehend gezeigt aus. (Eine spezielle Herausforderung ist es, dies so geschickt zu machen, dass die ganze Zeichnung mit nur einer while-Schleife erzeugt wird.) Aufgabe 33 Schafftst du es, mit Hilfe einer while-Schleife die nebenstehend gezeigte Grafik zu erzeugen? Tipp: Lasse von aussen gegen innen zeichnen. und verwende Transparenz. Ein paar Zahlenrechnereien Aufgabe 34 Überlege dir, was das folgende Programm macht: int n = 72931; // oder eine andere natürliche Zahl int s = 0; while (n>0) { s = s + n % 10; n = n / 10; } println("Das Resultat ist "+s); Aufgabe 35 Was wird hier berechnet? Erkläre, wie das Programm abläuft int n=32; // oder eine andere natürliche Zahl int res = 0; int b=1; while(n>0) { res += (n % 2) * b; n = n / 2; b *= 10; } println("Das Resultat ist "+res); Bedingungen Die while-Schleife wird über eine Bedingung gesteuert, also über einen logischen Ausdruck, der entweder "wahr" oder "falsch" ist. Sehen wir uns die Schreibweisen einiger solcher Bedingungen an: x < 100 x ist kleiner als 100 x > 100 x ist grösser als 100 x <= 100 x ist kleiner oder gleich 100 x >= 100 x ist grösser oder gleich 100 x == 100 x ist gleich 100 x != 100 x ist ungleich 100 Mehrere solche Ausdrücke können über ein logisches Und oder ein logisches Oder verknüpft werden. So ist x > 20 && x < 100 eine Verknüpfung mit dem logischen Und. Die Verknüpfung ist genau dann wahr, wenn beide Teilausdrücke wahr sind. x < 20 || x > 100 eine Verknüpfung mit dem logischen Oder. Sie ist genau dann wahr, wenn mindestens einer der beiden Teilausdrücke wahr ist. Aufgabe 36 Bestimme, ob für die Werte x = 80 und y = 120 die angegebenen Ausdrücke wahr oder falsch sind: a) x < 100 || y > 200 b) x < 100 && y > 200 c) x < 50 && y > 200 d) x < 50 || y > 200 e) x != 50 && y != 120 f) x! = 50 || y != 120 g) x != 50 && y == 120 h) x != 50 || y == 120 Verschachtelung von Schleifen Schleifen lassen sich auch verschachteln. Wenn wir beispielsweise eine Übersicht aller Farben gewinnen wollen, bei denen der Rot- und der Grünanteil kontinuierlich ändert, die aber keinen Blauanteil haben, so können wir dies mit einer Farbpalette bekommen, wie sie nebenstehend dargestellt ist. Von links nach rechts nimmt der Rot-Wert zu (er beginnt links bei 0 und endet rechts bei 255), von oben nach unten der Grünwert. Die Übersicht besteht nun aus 256 × 256 kleinen Quadraten, die je mit einer anderen Kombination von Rot- und Grün-Werten gefüllt werden. Dazu beginnen wir mit einer Schleife, die von links nach rechts die Rotwerte ändert (es ist dies die Schleife über der Variablen r). Für jeden Wert von r starten wir eine zweite Schleife über den Grünwert, indem der Wert der Variable g von 0 bis maximal 255 läuft. Das entsprechende Programm sieht so aus: // Processing-Sketch: Verschachtelung von Schleifen_1a.pdeint r;int g;size(512, 512);noStroke();r = 0;while (r<256) { // Schleife über die Rotwerte g = 0; while (g<256) { // Schleife über die Grünwerte fill(r, g, 0); rect(2*r, 2*g, 2, 2); g = g+1; } r = r+1;} Auf der nächsten Seite siehst du den Ablauf als Struktogramm in Pseudocode geschrieben. r := 0 solange r < 256 g := 0 solange g < 256 setze Farbe (r, g, 0) zeichne Quadrat mit Seitenlänge 2 bei (2·r, 2·g) erhöhe g um 1 erhöhe r um 1 Aufgabe 37 Was würde passieren, wenn die Anweisung g=0; vor der Zeile mit while (r<256) stehen würde? Aufgabe 38 Lasse dir die Palette aller Rot - Blau - Kombinationen zeichnen. Aufgabe 39 Schreibe ein Programm, welches in einem 610 × 610 - Fenster vertikal und auch horizontal je 15 Kreise mit Durchmesser 30 zeichnet. Tipp: Die Rotschattierung eines Kreises kannst du aus der Summe der Koordinaten des Mittelpunkts bestimmen, indem du sie durch 5 teilst. Aufgabe 40 Verwende zwei verschachtelte Schleifen, um das folgende Muster zu zeichnen. (Die Grössen kannst du frei wählen.) Iterationen: die for-Schleife Sehen wir uns den Aufbau einer while-Schleife an, so besteht dieser aus den folgenden Teilen: • einem Startwert für die Variable, über welche die Ausführungsbedingung der while-Schleife kontrolliert wird, • der Ausführungsbedingung selbst, • einer Anweisung, welche die Variable bei jedem Durchgang ändert, • weiteren Anweisungen, die mit der obigen zu einem Block zusammengefasst sind. Diesen Aufbau können wir mit einer for-Schleife noch etwas kompakter haben. Ihr Aufbau ist for(Anfangswert; Ausführungsbedingung; Änderung der Variable) Anweisungsblock Beispielweise also int i; for(i=0; i<12; i=i+1) { Anweisungen } Tipp: Statt i = i+1 geht kürzer auch die Anweisung i += 1, oder noch kürzer i++. Aufgabe 41 Verwende eine for-Schleife, um die 10 Quadrate in einem 620 × 200 - Fenster zu erzeugen. Aufgabe 42 Mit einer zweiten, verschachtelten for-Schleife kannst du nun die Grafik erweitern: Aufgabe 43 Verwende die Variablen der Schleifen, um auch die Farben wie abgebildet zu verändern. Aufgabe 44 Die nebenstehende Grafik besteht aus 200 konzentrischen Kreisen, deren Farbe von aussen nach innen stärker wird. Schreibe ein Programm, das diese Grafik mit Hilfe einer for-Schleife erzeugt. (Hinweis: Du musst die Grafik von aussen nach innen erzeugen, damit die kleineren Kreisflächen durch die grösseren nicht überdeckt werden.) Aufgabe 45 Die Anweisung random(255); erzeugt eine Zufallszahl zwischen 0 und 255. Mit fill(random(255), random(255), random(255)); erzeugst du daher zufällige Werte für den Rot, Grün- und Blauanteil einer Füllfarbe. Verwende dies, um 200 auf 200 Quadrate von je 2 Pixel Seitenlänge mit je einer Zufallsfarbe zu versehen. Aufgabe 46 In einem 400 × 400 - Fenster soll die Grössen der Quadrate von links oben nach rechts unten jeweils um 5 Pixel vom Startwert 0 her bis 195 anwachsen, wobei auch die linken, oberen Ecken der Quadrate diagonal nach rechts unten wandern. Du kannst entweder alle Quadrate weiss machen, oder sie wie gezeigt einfärben. Bedingungen: if - else Ein weiteres wichtiges Element ist die bedingte Verzweigung: Anhand einer Bedingung wird entschieden, wie weitergefahren werden soll. Der Programmablauf verzweigt dadurch, bevor er ab einem gewissen Punkt dann meist wieder zusammenläuft. Als Struktogramm sieht dies so aus: wahr Bedingung falsch Anweisungen für wahr Anweisungen für falsch weitere Anweisungen für wahr oder falsch Ein Beispiel ist (in Pseudocode) falls (b < a) r erhält den Wert von a sonst r erhält den Wert von b Ausgabe: r Ist b kleiner als a, so wird r gleich dem Wert von a gesetzt, andernfalls gleich dem Wert von b. Damit erhält r in jedem Fall den grösseren der beiden Werte a und b; das Programm bestimmt also das Maximum der beiden Zahlen und gibt dieses aus. Die Umsetzung in Processing / Java ist: if (b < a) { r = a; } else { r = b; } println(r); Nach dem Schlüsselwort if folgt eine logische Aussage. Ist sie wahr, so wird direkt weitergefahren und die folgende Anweisung ausgeführt. Sollen es auch mehr als nur eine Anweisung sein können, müssen sie durch geschweifte Klammern zu einem Block zusammengefasst werden. (Im obigen Beispiel könnten die geschweiften Klammern auch weggelassen werden, da es sich wirklich nur um eine einzige Anweisung handelt.) Soll im Fall, dass die Aussage falsch ist, etwas anderes gemacht werden, so folgt das Schlüsselwort else und wiederum ein Block von Anweisungen. Falls dieser Block leer ist, kann else auch weggelassen werden. Möglich wäre also auch r = a; // wird auf jeden Fall gemacht if (b>a) { r = b; // wird nur ausgeführt, wenn b>a ist } println(r); // r ist jetzt auf jeden Fall der grössere der Werte von a und b Aufgabe 47 Was bewirken die folgenden Zeilen? if(a<0) a = -a; Aufgabe 48 Welchen Wert haben n und x nach den folgenden Zeilen: n = 10; if(z % 2 == 1) { x = 3*z+1; } else { x = z/2; } n++; falls a) z = 5 ist, b) z = 4 ist. Aufgabe 49 Schreibe die folgenden Zeilen ab und überlege dir dabei, was sie bewirken werden: // Processing-Sketch: Quadrat Rechteck_1a.pdeint i;size(650, 200);background(200, 250, 200); // hellgrünnoStroke();for (i=0; i<11; i++) { if (i%2==0) { fill(200, 140, 0);// orange rect(5+i*60, 80, 40, 40); } else { fill(50, 20, 120); // lila rect(5+i*60, 40, 40, 120); }} Ändere das Programm nun so ab, dass jeweils zwei orange-farbene Quadrate und nur ein lila-farbener Balken gezeichnet werden. Für die folgenden Aufgaben verwenden wir ein Grundgerüst, das 10 auf 10 Kreisscheiben zeichnet: // Processing-Sketch: Loch-Blech_1a.pdeint i, j;size(500, 500);background(0);for (i=0; i<10; i++) { for (j=0; j<10; j++) { ellipse(25+i*50, 25+j*50, 40, 40); }} Aufgabe 50 Erweitere dieses Programm jeweils um eine Bedingung für das Einfärben der Kreise, so dass a) die Kreise aller ungeraden Spaltennummern grün gefärbt sind. (Mit Spaltennummer ist hier der Wert der Variable i gemeint.) b) alle diejenigen Kreise grün sind, deren Summe von Spalten- und Zeilennummer gerade sind. c) alle Kreise grün sind, deren Spalten- oder Zeilennummern (oder auch beide) Vielfache von 3 sind. Erzeuge ebenso die folgenden Muster: d) e) f) Tipps: Für diese Aufgabe kann die Restbildung gut gebraucht werden, so ergibt i%2 beispielsweise den Rest bei Teilung durch 2. Denke auch daran, dass logische Aussagen über das logische Und "&&" und das logische Oder "||" miteinander verknüpft werden können. Verschachtelung mehrerer if-else-Bedingungen Eine Verzweigung in mehr als zwei Wege ist durch eine Verschachtelung von if-else-Bedingungen möglich. Als Struktogramm sieht dies so aus: wahr 1 Bedingung 1 falsch 1 Anweisungen für wahr 1 wahr 2 Bedingung 2 falsch 2 Anweisungen falsch 1 wahr 2 Anweisungen falsch 1 falsch 2 weitere Anweisungen für wahr oder falsch Ist die Bedingung 1 wahr, so werden direkt die entsprechenden Anweisungen abgehandelt. Ist sie jedoch falsch, erfolgt die Überprüfung einer zweiten Bedingung, die auf zwei weitere Stränge führt. Damit kann aus drei möglichen Anweisungsblöcken gewählt werden. Die direkte Umsetzung mit Processing sieht beispielsweise so aus: if (a>b && a>c) { // a grösser als a und b r = a; } else { if(b>c) { r = b; } else { r = c; } } Java und damit auch Processing lassen aber auch eine etwas elegantere Schreibweise zu, die genau das Gleiche bewirkt: if (a>b && a>c) { // a grösser als a und b r = a; } else if(b>c) { r = b; } else { r = c; } (Dieses Programm bestimmt aus drei Werten a, b und c den höchsten und speichert ihn in r.) Aufgabe 51 Das folgende Programm zeichnet das nebenstehend dargestellte Muster: // Processing-Sketch: Loch-Blech farbig_1a.pdeint i, j;size(500, 500);background(0);for (i=0; i<10; i++) { for (j=0; j<10; j++) { if (i%3==0) // Rest 0 bei Teilung durch 3 fill(40, 255, 40); else if (i%3==1) // Rest 1 bei Teilung durch 3 fill(180, 20, 20); else // Rest 2 bei Teilung durch 3 fill(255); ellipse(25+i*50, 25+j*50, 40, 40); }} Zeichne auch die folgenden Grafiken: a) b) c) Tipp: Betrachte für die Teilaufgaben b) und c) die Reste bei Teilung durch 3 oder 4. AUTOR: Harald Pierhöfer DIN A4 ausdrucken ********************************************************* Impressum: Fritz Prenninger, Haidestr. 11A, A-4600 Wels, Ober-Österreich, mailto:[email protected] ENDE |
Processing > Einstieg in Processing >