Karel the robot

Ich möchte euch heute Karel den Roboter vorstellen. In den 1970er-Jahren kam Rich Pattis, ein Doktorand aus Stanford, zu dem Schluss, dass es einfacher sei, die Grundlagen des Programmierens zu vermitteln, wenn die Schüler die grundlegenden Ideen in einer einfachen Umgebung erlernen könnten, die frei von den Komplexitäten ist, die die meisten Programmiersprachen charakterisieren. Rich entwarf eine einführende Programmierumgebung, in der Schüler einem Roboter beibringen, einfache Probleme zu lösen. Dieser Roboter wurde Karel genannt, nach dem tschechischen Dramatiker Karel Čapek, dessen Stück R.U.R. aus dem Jahr 1923 erschien. (Rossums Universal Robots) gab der englischen Sprache das Wort Roboter.

Karel der Roboter war ein ziemlicher Erfolg. Deshalb setze auch ich ihn für meine Einführungskurse in Algorithmik und Programmieren einsetzen. Bisher habe ich meistens das Projekt von Fred Overflow genutzt, um mit Karel die Programmiergrundlagen zu vermitteln. Mit dem Stanford Projekt ist es endlich möglich, das Programmieren von Anfang an mit Python-Code zu realisieren.

Karels Welt

Karels Welt ist definiert durch horizontal (Ost-West) und vertikal (Nord-Süd) verlaufende Spalten. Der Schnittpunkt einer Zeile und einer Spalte wird als Ecke bezeichnet. Karel kann nur an Ecken positioniert werden und muss in eine der vier Standard-Himmelsrichtungen (Norden, Süden, Osten, Westen) zeigen. Unten sehen Sie ein Beispiel für eine Karel-Welt. Hier befindet sich Karel an der Ecke von 1. Reihe und 1. Spalte, nach Osten ausgerichtet.

n diesem Beispiel sind mehrere andere Bestandteile von Karels Welt zu sehen. Das Objekt vor Karel ist ein Piepser. Wie in Rich Pattis‘ Buch beschrieben, sind Piepser „Plastikkegel, die ein leises Piepgeräusch von sich geben“. Karel kann einen Piepser nur erkennen, wenn er sich an der gleichen Ecke befindet. Die durchgezogenen Linien im Diagramm sind Wände. Mauern dienen als Barrieren in Karels Welt. Karel kann nicht durch Wände gehen, sondern muss um sie herum gehen. Karels Welt ist immer von Wänden an den Rändern begrenzt, aber die Welt kann unterschiedliche Dimensionen haben, je nachdem, welches spezifische Problem Karel lösen muss.

Karels Befehle

Wenn Karel ab Werk ausgeliefert wird, reagiert es auf eine sehr kleine Anzahl von Befehlen. Probieren wir die Befehle aus. Verwenden Sie die Schaltflächen unten, um die „Welt“ mit dem „Ziel“ in Einklang zu bringen:

Die einzelnen Befehle bewirken Folgendes:

BefehlBeschreibung
move()Bittet Karel, einen Block vorwärts zu gehen. Karel kann nicht auf einen move()Befehl reagieren, wenn ihm eine Wand den Weg versperrt.
turn_left()Fordert Karel auf, sich um 90 Grad nach links (gegen den Uhrzeigersinn) zu drehen.
pick_beeper()Bittet Karel, einen Piepser aus einer Ecke aufzuheben und bewahrt den Piepser in seiner Piepsertasche auf, die eine unendliche Anzahl von Piepsern aufnehmen kann. Karel kann nicht auf einen pick_beeper()Befehl reagieren, es sei denn, es gibt einen Piepser an der aktuellen Ecke.
put_beeper()Bittet Karel, einen Piepser aus dem Beutel zu nehmen und ihn an der aktuellen Ecke abzulegen. Karel kann nicht auf einen put_beeper()Befehl reagieren, es sei denn, es befinden sich Piepser in seinem Piepserbeutel.

Das leere Klammerpaar, das in jedem dieser Befehle angezeigt wird, ist Teil der gemeinsamen Syntax von Karel und Python und wird verwendet, um den Aufruf des Befehls anzugeben. Letztendlich werden die Programme, die Sie schreiben, zusätzliche Informationen in den Klammern einfügen, aber solche Informationen sind nicht Teil der primitiven Welt der Karel. Diese Klammern sind daher in den Standard-Karel-Programmen leer, aber Sie müssen daran denken, sie trotzdem einzufügen.

Wenn Karel versucht, etwas Illegales zu tun, z. B. durch eine Wand zu gehen oder einen nicht vorhandenen Piepser aufzuheben, tritt eine Fehlerbedingung auf.

Karels Befehle werden nicht von selbst ausgeführt. Stattdessen müssen Sie sie in ein Karel-Programm integrieren. In Kapitel 2 haben Sie die Möglichkeit, ein paar einfache Karel-Programme zu sehen!

Karel programmieren

Aufgabe 1

vorher
nachher

Neue Funktionen definieren

Obwohl das obige FirstKarel-Programm zeigt, dass es möglich ist, die turn_right()Operation nur mit den in FirstKarel eingebauten Befehlen auszuführen, ist das resultierende Programm konzeptionell nicht besonders klar. In Ihrem mentalen Design des Programms dreht sich Karel nach rechts, wenn es die Spitze der Kante erreicht. Die Tatsache, dass Sie dafür drei turn_left()Befehle verwenden müssen, ist ärgerlich. Es wäre viel einfacher, wenn Sie einfach turn_right() sagen könnten und Karel diesen Befehl verstehen würde. Das resultierende Programm wäre nicht nur kürzer und einfacher zu schreiben, sondern auch deutlich besser zu lesen.

Glücklicherweise ermöglicht es die Programmiersprache Karel, neue Befehle einfach durch das Einfügen neuer Funktionsdefinitionen zu definieren. Wann immer Sie eine Sequenz von Karel-Befehlen haben, die eine nützliche Aufgabe ausführt, z. B. das Drehen nach rechts, können Sie eine neue Funktion definieren, die diese Befehlssequenz ausführt. Das Format zum Definieren einer neuen Karel-Funktion ähnelt weitgehend der Definition von main() in den vorherigen Beispielen, bei der es sich um eine eigenständige Funktionsdefinition handelt. Eine typische Funktionsdefinition sieht folgendermaßen aus:

def turn_right():
        turn_left()
        turn_left()
        turn_left()

Probleme zerlegen

Aufgabe2: Fülle das Schlagloch

Um mehr von der Macht zu veranschaulichen, die mit der Definition neuer Funktionen einhergeht, ist es nützlich, Karel etwas Praktischeres tun zu lassen, als einen Piepser von einem Ort zum anderen zu bewegen. Die Straßen scheinen oft reparaturbedürftig zu sein, und es könnte lustig sein zu sehen, ob Karel Schlaglöcher in seiner abstrakten Welt füllen kann. Stellen Sie sich zum Beispiel vor, dass Karel auf der „Straße“ steht, die in der linken Abbildung zu sehen ist, eine Ecke links von einem Schlagloch in der Straße. Karels Aufgabe ist es, das Loch mit einem Piepser zu füllen und zur nächsten Ecke zu gehen. Das Diagramm auf der rechten Seite zeigt, wie die Welt nach der Programmausführung aussehen sollte.

vorher
nachher
  1. Ermittle eine einfache Lösung für dieses Problem
  2. Versuche Funktionen zu definieren, die ein Programm in folgender Form ermöglichen:
def main():
    move()
    fill_pothole()
    move()

Schleifen

For-Schleife

Die For-Schleife hilft dir Sachen wiederholen. Die For-Schleife ist eine klassische Zählschleife. Das heißt, es steht von Anfang an fest, wie oft die Schleife durchlaufen wird. Die Schleife aus untenstehenden Beispiel wird 4-mal durchlaufen und i nimmt die Werte 0 bis < 4 (also 3) an.

for i in range(4):
    print(i)

Das Programm gibt also die Zahlen 0 bis 3 aus.

While-Schleife

Die While-Schleife wird stattdessen so oft durchlaufen, solange die Bedingung erfüllt ist. Man könnte mit einer While-Schleife auch eine klassische Zählschleife bauen, aber natürlich macht man das in der Praxis nicht.

i = 0
while i < 4:
    print(i)
    i= i + 1

Hier ist eine Liste mit allen Bedingungen, die Karel kennt

BedingungGegenteilErläuterung
front_is_clear()front_is_blocked()Gibt es vor Karel eine Wand?
beepers_present()no_beepers_present()Gibt es auf dem aktuellen Feld einen Beeper?
left_is_clear()left_is_blocked()Gibt es links von Karel eine Wand?
right_is_clear()right_is_blocked()Gibt es rechts von Karel eine Wand?
beepers_in_bag()no_beepers_in_bag()Hat Karel noch eine Beeper in seiner Tasche?
facing_north()not_facing_north()Schaut Karel nach Norden?
facing_south()not_facing_south()Schaut Karel nach Süden?
facing_east()not_facing_east()Schaut Karel nach Osten?
facing_west()not_facing_west()Schaut Karel nach Westen?
Hier ist eine Liste mit allen Bedingungen, die Karel kennt

Löse Aufgabe 3 mit For- und mit While-Schleife

Snake programmieren

Ladet euch die Datei Snake_unvollstaendig.sb3 herunter und ladet sie in scratch.mit.edu wieder hoch. 

Erklärt, wie die Körpersegmente entstehen und wieder verschwinden.

Erweitert das Programm so, dass ein vollwertiges Snake-Spiel entsteht. Folgende Funktionen sollen ergänzt werden:

  1. Steuerung mit den restlichen Pfeiltasten →, ↓ und ←
  2. Game-Over-Bedingung: Falls der Rand ODER die Farbe des eigenen Körpers berührt wird…
  3. Wenn der Apfel berührt wurde, dann sollen die Punkte um 1 hochgezählt werden. Löst dies mit einer Variable „Punkte“.
  4. Die Anzahl der Körpersegmente soll der Punktezahl entsprechen. Tipp: Experimentiert mit der Zeit, die das geklonte Körpersegment verweilt, bevor es sich selbst löscht.
  5. Ausgabe der Punkte bei Game Over
  6. Die Geschwindigkeit soll sich erhöhen, wenn ein Punkt erhalten wurde.

Fallen euch noch weitere Funktionen ein?

Zeichne ein Schachbrett mit Turtle-Graphics

  1. Erzeuge ein Fenster mit 640 x 640 Pixel und zeichne 64 Qudrate (Seitenlänge 80 Pixel) abwechselnd in den Farben Schwarz und Weiß. Schau dir dazu die folgenden Befehle an:
    • Screen().setup()
    • begin_fill(), end_fill(), fillcolor()
    • bgcolor()
  2. Erkunde zunächst den Aufbau des Fensters. Stichwort „absolute Koordinaten“. Bisher haben wir Turtle mit forward() immer in eine vorher festgelegt Richtung gehen lassen.
    Schau dir folgende Befehle/Funktionen dazu an
  3. Für das abwechselnde Einfärben braucht ihr noch den folgenden Operator.
    Hier wird erklärt, wie der Modulo-Operator funktioniert. Versucht mal herauszufinden, wie ihr in Einsetzen könnt.

Aufgabe für den 28.11.2023 Erstelle eine HTML-Seite

Erstellt eine Internetseite mit mindestens 3 Unterseite (Also insgesamt 4 html-Dateien + 1 css-Datei) in der über ein Menü (für jede Seite ein Link) miteinander verknüpft sind zu einem Thema eurer Wahl.

Sucht euch ein Thema aus, am besten eins das euch wirklich interessiert, sonst wird es schnell langweilig.

Jede Seiten sollten mehrere Überschriften, min. 200 Zeichen Text und min. 3 Bilder enthalten.

Formatiert die Seiten mit CSS. Informiert euch auf selfhtml.org weiter zu CSS Eigenschaften, die ihr benötigt. Verwendet min. 10 Eigenschaften pro Seite. Dort könnt ihr auch nochmal nachlesen wie

Abhängig von eurem Wissensstand könnt ihr euch hier weiteren Informationen holen.

Für eurer Ergebnis gibt es nächste Stunde Feedback und eine Note. Anschließend werden wir an der Seite weiterarbeiten und weitere Feedbackschleifen werden folgen.

Aufgaben für den 28.11.2023 – Einführung Funktionen

Wir haben in den letzten Stunden schon oft die Buildin-Funktioen print() und input() verwendet. Heute lernt ihr, wie ihr selbst Funktionen in Python definieren könnt.

Video 1: Einführung Funktionen
Video 2: Funktionen mit Parametern
Video 3: Funktionen mit Rückgabewert

Schaut euch die drei Videos an und versucht nachzuvollziehen, was dort besprochen wird.
Jetzt sollte das Prinzip klar sein!

  1. Programmiert zunächst maximum-Funktion aus dem Video 3 nach, falls ihr das noch nicht gemacht habt.
  2. Programmiert eine weitere Funktion max_of_three(param1, param2, param3), die das Maximum aus 3 Parametern ermittelt. (Nicht schummeln und die eingebaute max-Funktion nutzen).
  3. Wenn die Funktion aus Aufgabe 2 ohne Syntax-Error läuft. Tausche mit deinem Nachbarn kurz die Plätze und lass die Funktion von ihm testen und teste seine.

Aufgabe 2: Zahlenratespiel

Im unteren grauen Feld findest du den Anfang eines Python-Programms mit vielen Kommentaren. Versuche die Kommentare in Python-Code zu übersetzen und deinen Programm-Code anschließen zu debuggen bis du ein funktionierendes Zahlenratespiel hast. Also Text aus der grauen Box nach Thonny kopieren und loslegen!

Das Programm soll zunächst “Willkommen beim Zahlenratespiel ! Errate eine Zaufallszahl zwischen 1 und 100″ ausgeben und dann so lange die Eingabeaufforderung „Gib eine Zahl ein: “ ausgeben bis die Zahl erraten ist. Wird eine Zahl eingegeben, bekommt der Spieler Rückmeldung, ob seine Zahl größer oder kleiner ist als die Zufallszahl des Computers. Wird die Zahl erraten, gibt das Programm aus, wie viele Versuche der Spieler benötigt hat.

# Import der Zufallszahlen-Library - einfach so lassen
import random

# eine eigene Input funktion die solange nervt bis man wirklich einen Int eingibt
def intInput(Eingabeaufforderung):
    result = False
    while not(result):
        value = input(Eingabeaufforderung)
        # Hier wird auch schon Eror-Handling verwendet
        try:
            zahl = int(value)
        except ValueError:
            result = False
        else:
            result = True
    return zahl

# Zufällige Zahl zwischen 1 und 100 auswählen
ZielZahl = random.randint(1, 100)
# Die Variable ZielZahl enthält jetzt ein Zufallszahl zwischen 1 und 100

# Hier werden zwei Variablen anlegen, die du vielleicht brauchst
versuche = 0
geraten = False

# Der Spieler wird in zum Spielen eingeladen
print("Willkommen beim Zahlenratespiel! Errate die Zahl zwischen 1 und 100.")

# Wiederhole die Ausgabe "Gib eine Zahl ein: " bis die Zahl erraten wurde
while xyz: # xyz müsst ihr durche eine funktionierende Bedingung ersetzt werden
    # Lies eine Zahl vom Benutzer ein
    # benutze hier am besten unsere neuen Funktion intInput() um tatsäclich eine Zahl zurückzubekommen
    
    # Entscheide ob die Zahl, die eingegeben wurde größer oder kleiner als die Zielzahl ist, oder ob die Zielzahl erraten wurde 
    # Dazu müst ihr euch evtl. nochmal die Unterlagen zu Verzeigungen anschauen.
    # Gibt eine entsprechende Meldung aus
    # Wenn die Zahl erraten wurde gib aus wie viele Versuche benötigt wurden