{ "cells": [ { "cell_type": "markdown", "id": "126aa47b", "metadata": {}, "source": [ "# Fallstudie 3: Bedingungen und Rekursion\n", "\n", "#### Patrick Schnider, Marcel Lüthi
Departement Mathematik und Informatik, Universität Basel" ] }, { "cell_type": "markdown", "id": "31316514", "metadata": {}, "source": [ "### Boolsche Ausdrücke" ] }, { "cell_type": "markdown", "id": "01c3551b", "metadata": {}, "source": [ "Wenn wir Situationen in der Programmierung beschreiben, haben wir es oft mit relativ komplexen Boolschen Ausdrücken zu tun. Wir müssen lernen diese zu lesen, verstehen und, wo möglich, zu vereinfachen. \n", "\n", "Ein Beispiel, welches zu einem komplexen boolschen Ausdruck führt ist, wenn wir die Punkte in der folgenden farbigen Fläche charakterisieren möchten\n", "\n", "![shape](images/shape.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "7a313c8e", "metadata": {}, "outputs": [], "source": [ "class BooleanExpression {\n", " public static boolean isInside(double x, double y) {\n", " // Schreiben Sie hier Ihre Methode\n", " return true;\n", " }\n", " \n", " public static void main(String[] args) {\n", " // Testen Sie hier Ihre Methode\n", " }\n", "}\n", "BooleanExpression.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "d6f31416", "metadata": {}, "source": [ "\n", "#### Miniübung\n", "\n", "* Schreiben Sie die Methode `isInside` so um, dass diese `true` zurück gibt, wenn die durch `x` und `y` gegebene Koordinate innerhalb der farbigen Fläche liegt.\n", "* Testen Sie die Methode `isInside` mit verschiedenen Werten\n" ] }, { "cell_type": "markdown", "id": "35f29149", "metadata": {}, "source": [ "### Boolsche Algebra" ] }, { "cell_type": "markdown", "id": "c46c5215", "metadata": {}, "source": [ "Um komplexe boolsche Ausdrücke zu verwenden, können wir die Regeln von *De-Morgan* verwenden:" ] }, { "cell_type": "markdown", "id": "fca72997", "metadata": {}, "source": [ " !(A && B) ist gleich !A || !B\n", " !(A || B) ist gleich !A && !B " ] }, { "cell_type": "markdown", "id": "156b2dce", "metadata": {}, "source": [ "#### Miniübung\n", "\n", "* Schreiben Sie ein Programm, welches diese Regeln überprüft. " ] }, { "cell_type": "code", "execution_count": null, "id": "80257c94", "metadata": {}, "outputs": [], "source": [ "class BooleanTest {\n", " \n", " public static void main(String[] args) {\n", " // Schreiben Sie hier Ihren Code\n", " }\n", " \n", "}\n", "\n", "BooleanTest.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "76ec5dd2", "metadata": {}, "source": [ "#### Bindung von Operatoren\n", "\n", "Bei der Arithmetik kennen wir die Punkt vor Strich-Regel. Gilt so eine Regel auch bei `||`, `&&` und `!`? Experimentieren Sie" ] }, { "cell_type": "code", "execution_count": null, "id": "f7a2104c", "metadata": {}, "outputs": [], "source": [ "class OperationOrder {\n", " \n", " public static void main(String[] args) {\n", " // Schreiben Sie hier Ihren Code\n", " }\n", "}\n", "\n", "OperationOrder.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "3527d5cf", "metadata": {}, "source": [ "### Hochhäuser zeichnen" ] }, { "cell_type": "markdown", "id": "f8b5028a", "metadata": {}, "source": [ "Wir kommen nun zurück auf unsere Zeichnungsaufgabe vom letzten Mal. Dazu laden wir zuerst wieder die Turtle Bibliothek." ] }, { "cell_type": "code", "execution_count": null, "id": "775bb506", "metadata": {}, "outputs": [], "source": [ "%mavenRepo shapemodelling-repo https://shapemodelling.cs.unibas.ch/repo/\n", "%maven ch.unibas.informatik:jturtle:0.7" ] }, { "cell_type": "code", "execution_count": null, "id": "b70caaac", "metadata": {}, "outputs": [], "source": [ "import static ch.unibas.informatik.jturtle.TurtleCommands.*;\n", "import java.awt.Color;" ] }, { "cell_type": "markdown", "id": "0c7a9e33", "metadata": {}, "source": [ "Der Folgende Code zeichnet ein vier-stöckiges Hochhaus. " ] }, { "cell_type": "code", "execution_count": null, "id": "67d6ba48", "metadata": {}, "outputs": [], "source": [ "class Building {\n", " public static void drawRectangle(double xPos,\n", " double yPos,\n", " double width,\n", " double height) {\n", " reset(); // set turtle to origin and make it face upwards\n", " penUp();\n", " goTo(xPos, yPos);\n", " penDown();\n", " \n", " forward(height);\n", " turnRight(90);\n", " forward(width);\n", " turnRight(90);\n", " forward(height);\n", " turnRight(90);\n", " forward(width); \n", " }\n", " \n", " \n", " public static void drawFourStoreyBuilding(double xPos,\n", " double yPos,\n", " double width,\n", " double height) {\n", " double heightOfStorey = height / 4.0;\n", " drawRectangle(xPos, yPos, width, heightOfStorey);\n", " drawRectangle(xPos, yPos + heightOfStorey, width, heightOfStorey);\n", " drawRectangle(xPos, yPos + 2 * heightOfStorey, width, heightOfStorey);\n", " drawRectangle(xPos, yPos + 3 * heightOfStorey, width, heightOfStorey); \n", " }\n", " \n", " public static void main(String[] args) {\n", " clear();\n", " drawFourStoreyBuilding(0, 0, 30, 50);\n", " display(drawing());\n", " }\n", " \n", "}\n", "\n", "Building.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "56cacdd6", "metadata": {}, "source": [ "Mit if-Bedingungen können wir nun zwischen verschiedenen Hochhäusern unterscheiden, ohne dass wir jeweils eine komplett neue Methode schreiben müssen. Zum Beispiel können wir Hochhäuser mit und ohne Antenne auf dem Dach schreiben. " ] }, { "cell_type": "markdown", "id": "debd8aff", "metadata": {}, "source": [ "#### Miniübung\n", "\n", "* Sie wollen nun zwei Arten von 4-stöckigen Häusern zeichnen, nämlich mit oder ohne Antenne. Dies wollen Sie beim Aufruf der Methode angeben können. Ergänzen Sie die Methode um ein Argument `hasAntenna`. \n", "* Ergänzen Sie den Code so, dass, falls beim Aufruf gewünscht, eine Antenne gezeichnet wird (zum Beispiel durch einen weiteren Aufruf von drawRectangle).\n" ] }, { "cell_type": "code", "execution_count": null, "id": "347d2140", "metadata": {}, "outputs": [], "source": [ "class Building {\n", " public static void drawRectangle(double xPos,\n", " double yPos,\n", " double width,\n", " double height) {\n", " reset(); // set turtle to origin and make it face upwards\n", " penUp();\n", " goTo(xPos, yPos);\n", " penDown();\n", " \n", " forward(height);\n", " turnRight(90);\n", " forward(width);\n", " turnRight(90);\n", " forward(height);\n", " turnRight(90);\n", " forward(width); \n", " }\n", " \n", " \n", " public static void drawFourStoreyBuilding(double xPos,\n", " double yPos,\n", " double width,\n", " double height) {\n", " double heightOfStorey = height / 4.0;\n", " drawRectangle(xPos, yPos, width, heightOfStorey);\n", " drawRectangle(xPos, yPos + heightOfStorey, width, heightOfStorey);\n", " drawRectangle(xPos, yPos + 2 * heightOfStorey, width, heightOfStorey);\n", " drawRectangle(xPos, yPos + 3 * heightOfStorey, width, heightOfStorey); \n", " }\n", " \n", " public static void main(String[] args) {\n", " clear();\n", " drawFourStoreyBuilding(0, 0, 30, 50);\n", " display(drawing());\n", " }\n", " \n", "}\n", "\n", "Building.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "1083f9b3", "metadata": {}, "source": [ "#### Wiederholungen durch Rekursion ausdrücken\n", "\n", "Bisher hatten unsere Methoden eine grosse Einschränkung. Wir konnten immer nur Häuser mit einer fixen Anzahl Stockwerke zeichnen. Dank Rekursion können wir nun auch Methoden schreiben, bei denen man die Anzahl Stockwerke als Parameter angeben kann. \n", "\n", "Die Strategie ist wie folgt:\n", "- um ein $n$-stöckiges Gebäude zu zeichnen, zeichnen wir zuerst ein Rechteck und dann oben drauf ein $(n-1)$-stöckiges Gebäude.\n", "- um ein $0$-stöckges Gebäude zu zeichnen müssen wir nichts machen. " ] }, { "cell_type": "code", "execution_count": null, "id": "7a99f26c", "metadata": {}, "outputs": [], "source": [ "class Building {\n", " public static void drawRectangle(double xPos, double yPos, double width, double height) {\n", " reset(); // set turtle to origin and make it face upwards\n", " penUp();\n", " goTo(xPos, yPos);\n", " penDown();\n", " \n", " forward(height);\n", " turnRight(90);\n", " forward(width);\n", " turnRight(90);\n", " forward(height);\n", " turnRight(90);\n", " forward(width); \n", " }\n", " \n", " public static void drawBuilding() { // Fügen Sie hier die benötigten Argumente ein\n", " // Schreiben Sie hier Ihren Code\n", " }\n", " \n", " public static void main(String[] args) {\n", " clear();\n", " drawBuilding(); // Ergänzen Sie hier den Aufruf mit den benötigten Argumenten\n", " \n", " display(drawing());\n", " }\n", " \n", "}\n", "\n", "Building.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "bd5e33f1", "metadata": {}, "source": [ "#### Miniübungen\n", "\n", "* Können Sie mit dieser Strategie ein Programm schreiben, das ein $n$-Eck zeichnet?" ] }, { "cell_type": "code", "execution_count": null, "id": "c19fb828", "metadata": {}, "outputs": [], "source": [ "class Drawing {\n", " \n", " \n", " public static void main(String[] args) {\n", " // Schreiben Sie hier Ihren Code\n", " }\n", "}\n", "\n", "Drawing.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "6043dc15", "metadata": {}, "source": [ "### Die Schönheit der Rekursion" ] }, { "cell_type": "markdown", "id": "da39f3cf", "metadata": {}, "source": [ "Zum Schluss noch etwas Schönes. Wir können mittels Rekursion Fraktale Frafiken zeichnen. Fraktale sind gemoetrische Figuren, die als Teil jeweils wieder dieselbe Figur enthalten. Ein Beispiel dafür ist das Sierpinski Dreick. Diese ist aus drei Dreiecken zusammengesetzt, die selbst wieder aus drei Dreicken bestehen, die selbst wieder aus drei Dreicken bestehen, ...." ] }, { "cell_type": "code", "execution_count": null, "id": "a5b4e3e9", "metadata": {}, "outputs": [], "source": [ "public class Sierpinski {\n", " public static void drawSierpinski(double length, int depth) {\n", " if (depth==0){\n", " for (int i = 0; i < 3; i++) {\n", " forward(length);\n", " turnLeft(120);\n", " }\n", " }\n", " else {\n", " drawSierpinski(length/2.0 , depth-1);\n", " forward(length/2);\n", " drawSierpinski(length/2.0,depth-1);\n", " backward(length/2);\n", " turnLeft(60);\n", " forward(length/2);\n", " turnRight(60);\n", " drawSierpinski(length/2.0,depth-1);\n", " turnLeft(60);\n", " backward(length/2);\n", " turnRight(60);\n", " }\n", " }\n", " \n", " public static void main(String[] args) {\n", " home();\n", " clear();\n", " reset();\n", " penUp();\n", " goTo(-80, -80);\n", " turnRight(90);\n", " penDown();\n", " drawSierpinski(160, 7);\n", " display(drawing());\n", " }\n", "}\n", "\n", "Sierpinski.main(new String[0]);" ] }, { "cell_type": "markdown", "id": "2b98c806", "metadata": {}, "source": [ "#### Miniübung" ] }, { "cell_type": "markdown", "id": "1351c853", "metadata": {}, "source": [ "* Versuchen Sie den Aufgabe dieser Zeichnung zu verstehen, indem Sie das Dreieck mit unterschiedlichen Rekursionstiefen zeichnen.\n", "* Zusätzlich können Sie auch die Dreicke farbig einfärben." ] } ], "metadata": { "kernelspec": { "display_name": "Java [conda env:ijava]", "language": "java", "name": "conda-env-ijava-java" }, "language_info": { "codemirror_mode": "java", "file_extension": ".jshell", "mimetype": "text/x-java-source", "name": "Java", "pygments_lexer": "java", "version": "17.0.3-internal+0-adhoc..src" } }, "nbformat": 4, "nbformat_minor": 5 }