Dies ist eine alte Version des Dokuments!
FR
Minecraft mit Hilfe von Python steuern
Minecraft per Code steuern
Minecraft kann durch Programme gesteuert werden. Dabei kann die Programmierung mit Blöcken (wie in Scratch) oder durch Text-Programmierung (Python oder JavaScript) erfolgen.
Um in Minecraft Education programmieren zu können drückt man die Taste c. Tut man dies zum ersten Mal, so kann man den gewünschten Editor wählen. Am besten ist hier die Wahl „Make Code“, da man hier die freie Auswahl zwischen Blockprogrammierung, Python oder JavaScript hat. Wir werden Python für die Programmierung verwenden.
Grundlagen und vordefinierte Befehle
Absulute und relative Koordinaten
Man kann Positionen auf drei Arten angeben: absolut, relativ zur Befehlsquelle (Agent oder Spieler) bezüglich der Himmelsrichtung und relativ zur Befehlsquelle bezüglich der Blickrichtung.
| Befehl | Bedeutung |
|---|---|
world(x,y,z) | Absolute Position in der Welt |
pos(x,y,z) | Relativ zum Spieler/Agenten bez. Himmelsrichtung |
local_pos(x,y,z) | Relativ zum Spieler/Agenten bez. Blickrichtung |
Der Agent
Neben der Spielfigur gibt es in Minecraft Education auch einen sogenannten Agenten. Dabei handelt es sich um einen kleinen Roboter, den man mit den Agent-Befehlen steuern kann. Man kann dem Agenten Befehle erteilen und ihn dazu bringen, sich zu bewegen oder zu bauen. Der Agent hat sein eigenes Inventar, das man per Rechtsklick auf den Agenten einsehen und verändern kann. Man kann das Inventar auch durch den Befehl agent.set_item verändern (siehe weiter unten).
Den Agenten bauen lassen, oder direkt bauen
Man kann nun den Agenten dazu bringen, etwas für uns zu bauen, oder man kann auch direkt (ohne die Verwendung der Agenten bauen). Die folgenden beiden Programme setzen jeweils einen Gold- und einen Diamantblock an die absoluten Positionen (0,-60,10) und (0,-60,11):
blocks.place(GOLD_BLOCK,world(0,-60,10)) blocks.place(DIAMOND_BLOCK, world(0,-60,11))
agent.set_item(GOLD_BLOCK,1,1) # 1 Goldblock ins Fach 1 legen agent.set_item(DIAMOND_BLOCK,1,2) # 1 Diamantblock ins Fach 2 legen agent.teleport(world(0,-60,11), SOUTH) # zur Position teleportieren agent.set_slot(1) agent.place(BACK) # Block aus dem ausgewählten Fach hinter sich platzieren agent.move(FORWARD,1) agent.set_slot(2) agent.place(BACK)
Die definierten Befehle für den Agenten bzw. für die Blöcke findest du am besten, indem du in MakeCode in der linken Leiste einen Bereich wählst (Grundlagen, Spieler, Blöcke…) und dann den entsprechenden Befehl ins Code-Fenster ziehst.
Praktische Option, wenn man den Agenten bauen lässt (assist
Es kann praktisch sein, die Option assist zu setzen, wenn man mit dem Agenten baut. Dadurch kann man erreichen, dass der Agent bei jeder Bewegung aus dem aktiven Fach baut (dadurch muss man nicht jedes Mal agent.place(…) aufrufen) bzw. dass der Agent alle Hindernisse zerstört, die sich ihm in den Weg stellen.
agent.set_assist(PLACE_ON_MOVE, [TRUE/FALSE]) | Bauen, während Agent sich bewegt (Ja/Nein) |
agent.set_assist(DESTROY_OBSTACLES, [TRUE/FALSE]) | Hindernisse zerstören |
agent.set_assist(PLACE_FROM_ANY_SLOT, [TRUE/FALSE]) | Automatisch nächstes Fach wählen, wenn ein Fach leer ist |
Achtung: Wenn man im Kreativmodus ist, so ist das Material unlimitiert, d.h. es nimmt im Inventar des Spielers oder des Agenten nicht ab, wenn man baut.
Programmierkonzepte in Python
1. Variablen
Eine Variable ist ein Behälter, in dem Daten gespeichert werden können. Stelle dir z.B. einen Koffer vor, in dem du etwas aufbewahren kannst. Die Variable ist der Koffer und der Wert der Variablen ist der Inhalt dieses Koffers. Eine Variable erstellt man mit dem Gleichheitszeichen:
meinKoffer = 3
1.1 Dynamische Typisierung (Python) vs. statische Typisierung
Evtl. kennst du aus anderen Programmiersprachen die Regel, dass man Variablen vor ihrem ersten Gebrauch deklarieren muss. Dabei muss man den Namen und ihren Typ angeben, z.B. int a = 3 (in C#). Dadurch weiss der Compiler/Interpreter direkt, um welchen Typ von Variaben es sich handelt (hier eine ganze Zahl) und er kann ensprechend Platz im Speicher reservieren. Diese Variable kann danach aber nur den angegebenen Typ annehmen. Solche Programmiersprachen sind statisch typisiert. In Python ist dies nicht so: du kannst Variablen einfach definieren, indem du einem Variablennamen einen Wert zuweist. In derselben Variablen kannst du dann ganze Zahlen, Kommazahlen, Text oder auch komplexere Objekte (Listen etc.) speichern. Python ist dynamisch typisiert.
a = 1 # eine ganze Zahl (integer) print(a+1) a = "Ein Text" # Text (string) a = 2.13 # Kommazahl (float) a = True # Wahrheitswert (boolean)
1.2 Namen für Variablen und Funktionen
Wichtige Variablen oder Funktionen sollten (wenn möglich) Namen haben, die ihre Bedeutung erkennen lassen. Es gibt zwei Konventionen, die sich bei Namen mit mehreren Wörter etabliert haben:
| Camelcase | Bei Namen, die aus mehreren Wörtern bestehen, wird jeweils bei einem neuen Wort der erste Buchstabe grossgeschrieben. Der allererste Buchstabe jedoch klein (Bsp: anzahlGoldbloecke, rechtesFenster). |
| Pascalcase | Exakt dasselbe wie Camelcase, jedoch wird auch der erste Buchstabe gross geschrieben (Bsp: AnzahlGoldbloecke, RechtesFenster). |
| Snakecase | Bei Namen, die aus mehreren Wörtern bestehen, werden diese durch einen Unterstrich getrennt (Bsp. anzahl_goldbloecke, rechtes_fenster) |
1.3 Was bringen Variablen?
- Wenn man in einem Programm sehr häufig denselben Wert verwendet, kann man diesen in einer Variablen (oder Konstanten) speichern und dann im Programm diese Variable verwenden. Will man den Wert ändern, so kann man diesen zentral am Anfang bei der Variablendefinition ändern und die Ändreung wird dann überall im Programm aktiv.
- Häufig weiss man bei der Erstellung des Programms gar noch nicht, welchen Wert gewisse Daten haben (z.B. muss der Benutzer die Anzahl der Spieler eingeben, oder sein Alter etc.). Einer Variablen kann man dann zur Laufzeit des Programms den entsprechenden Wert zuweisen.
Zusammenfassend lässt sich sagen, dass durch Variablen die Daten in den Programmen flexiebler einsetzbar und besser anpassbar werden.
2. Eigene Funktionen definieren mit ''def''
2.1 Funktionen/Prozeduren (ohne Parameter und Rückgabewert)
Funktion oder Prozedur (die beiden Begriffe werden hier als Synonym betrachtet) bezeichnet ein Unterprogramm, das durch seinen Namen aufgerufen werden kann. Es gibt viele vordefinierte Funktionen in Python oder Minecraft (z.B. pow(a,b), agent.turn(LEFT)) aber sehr oft ist es sinnvoll, auch eigene Funktionen zu programmieren. Der Vorteil liegt auf der Hand: wenn mehrmals dieselben Anweisungen ausgeführt werden sollen, kann man diese als Funktion speichern und dann mehrmals aufrufen. Dadurch wird Redundanz (sich wiederholender, überflüssiger Code) vermieden und das Progamm wird strukturiert.
Funktionen erstellt man in Python durch den Befehl def. Wir können beispielsweise eine Funktion definieren, welche den Agenten eine Spirale bauen lässt und diese dann mehrmals aufrufen:
agent.set_assist(PLACE_ON_MOVE, True) # Agent baut, wenn er sich bewegt
agent.set_assist(DESTROY_OBSTACLES,True) # Agent zerstört Hindernisse beim Bauen
agent.set_item(SANDSTONE,64,1) # 64 Blöcke Sandstein ins erste Fach des Inventars legen
def baueSpirale():
drehRichtung = LEFT # Alternativ: drehRichtung = RIGHT
agent.move(FORWARD,1)
agent.turn(drehRichtung)
agent.move(FORWARD,2)
agent.turn(drehRichtung)
agent.move(FORWARD,3)
agent.turn(drehRichtung)
agent.move(FORWARD,4)
agent.turn(drehRichtung)
agent.move(FORWARD,5)
agent.turn(drehRichtung)
agent.move(FORWARD,6)
baueSpirale()
agent.move(FORWARD, 10)
baueSpirale()
agent.move(FORWARD, 10)
baueSpirale()
agent.move(FORWARD, 10)
baueSpirale()
agent.move(FORWARD, 10)
Aufgaben A
- Überlege dir, was der Agent genau baut, wenn man das oben angegebene Programm ausführt. Bei welcher Zeile des Codes beginnt der Agent mit dem Bauen?
- Überprüfe deine Überlegung, indem du das Programm in Minecraft einfügst und ausführst (evt. musst du zunächst den Agenten zu dir teleportieren. Im Chat kannst du das machen mit
/teleport @c @s) - Das angegebene Programm ist nicht sehr optimiert - es enthält viel Redundanz (überflüssiger, sich wiederholender Code) und es ist nicht gut anpassbar. Schreibe die Funktion um, so dass sie kürzer und eleganter wird (verwende dazu die unten erklärten Konzepte, z.B. einen Parameter in welchem man wählen kann, ob sie rechts- oder linksdrehend ist und eine
for-Schleife)
Oben wird die Variable drehRichtung innerhalb der Funktion baueSpirale definiert. Man kann sie dann nur innerhalb dieser Funktion verwenden: man spricht von einer lokalen Variablen.
Würde man die Variable ausserhalb der Funktion (ganz zu Beginn des Codes) definieren, dann wäre sie überall im Programm sichtbar, auch in den Funktionen. Man spricht dann von einer globalen Variable.
Globale Variablen kann man innerhalb einer Funktion nur ändern, wenn man dies in der Funktion mit dem Schlüsselwort global deklariert.
2.2 Funktionen mit Parametern
Wenn man mit def eine eigene Funktion definiert, kann man diese flexibler machen, indem man Parameter verwendet. Dies sind Variablen, die beim Aufruf der Funktion übergeben werden und dann innerhalb der Funktion wie lokale Variablen funktionieren. So könnte man z.B. eine Funktion Hochhaus(n) definieren, welches ein Hochhaus mit n Etagen baut. Wenn man die Funktion dann aufruft, muss man für n einen konkreten Wert angeben: z.B. Hochhaus(7).
Das Beispiel unserer Spirale können wir mit Parametern etwas eleganter gestalten: wir übergeben der Funktion die Drehrichtung als Parameter.
agent.set_assist(PLACE_ON_MOVE, True) # Agent baut, wenn er sich bewegt
agent.set_assist(DESTROY_OBSTACLES,True) # Agent zerstört Hindernisse beim Bauen
agent.set_item(SANDSTONE,64,1) # 64 Blöcke Sandstein ins erste Fach des Inventars legen
def baueSpiraleNeu(richtung):
agent.move(FORWARD,1)
agent.turn(richtung)
agent.move(FORWARD,2)
agent.turn(richtung)
agent.move(FORWARD,3)
agent.turn(richtung)
agent.move(FORWARD,4)
agent.turn(richtung)
agent.move(FORWARD,5)
agent.turn(richtung)
agent.move(FORWARD,6)
baueSpiraleNeu(TurnDirection.LEFT)
agent.move(FORWARD, 10)
baueSpiraleNeu(TurnDirection.RIGHT)
agent.move(FORWARD, 10)
baueSpiraleNeu(TurnDirection.LEFT)
agent.move(FORWARD, 10)
baueSpiraleNeu(TurnDirection.RIGHT)
agent.move(FORWARD, 10)
Nun können wir dieselbe Funktion verwenden, um rechtsdrehende und linksdrehende Spiralen zu bauen. Wir übergeben beim Aufruf der Funktion die Drehrichtung (baueSpiraleNeu(TurnDirection.Right)) und diese Drehrichtung ist dann innerhalb der Funktion an die Variable richtung gekoppelt (da wir bei der Definition der Funktion diesen Namen gewählt haben).
2.3 Funktionen mit Rückgabewert
Die bisher betrachteten Funktionen hatten keinen Rückgabewert (in einigen Büchern werden diese als Prozeduren bezeichnet). Eine Funktion kann jedoch auch einen Wert zurückgeben und dieser kann dann im Programm weiter verwenden und z.B. in einer Variablen gespeichert werden.
Im Minecraft hat z.B. die Funktion agent.get_orientation() einen Rückgabewert (die Blickrichtung des Agenten). Dadurch kann man z.B. schreiben:
direction1 = agent.get_orientation()
if direction1 == -90:
agent.turn(RIGHT)
Natürlich könnte man auch auf die Speicherung in der Variablen verzichten und direkt in der if-Abfrage die Orientierung verwenden:
if agent.get_orientation() == -90:
agent.turn(RIGHT)
Wenn man eigene Funktionen mit Rückgabewert definiert, so verwendet man das Schlüsselwort return. Sobald man einen Wert zurückgegeben hat, machen weitere Befehle in der Funktion keinen Sinn mehr, da diese ignoriert werden:
from math import sqrt
def mitterNachtsFormel(a,b,c):
d = b**2-4*a*c
if d < 0:
return False # False zurückgeben, da es keine Lösung gibt
else:
return [(-b+sqrt(d))/(2*a),(-b-sqrt(d))/(2*a)] # Liste mit den beiden Lösungen zurückgeben
2.4 Rekursive Funktionen
Funktionen können auch rekursiv definiert werden, d.h. sie rufen sich selbst auf. Beispiele:
def rec1(n):
if n<=1:
return
blocks.fill(RED_WOOL,pos(0,0,0),pos(n,0,n))
player.teleport(pos(1,1,1))
rec1(n-2)
rec1(10)
ef rec2(x,y):
if x<=1 or y>=30:
blocks.place(GOLD_BLOCK,pos(x,y,10))
else:
blocks.place(GRANITE, pos(x,y,10))
rec2(x-1,y+2)
rec2(x+1, y)
rec2(30,4)
Aufgaben B
- Überlege dir, was der Agent genau baut, wenn man das oben angegebene Programm
rec1ausführt. Wie könnte man das Programm ohne Rekursion programmieren? - Überlege dir dies auch für das Programm
rec2. Kannst du auch dieses Programm ohne Rekursion programmieren? - Welcher fundamentale Unterschied besteht zwischen den beiden Programmen? Wie wirkt sich dies auch den Zeit- und Speicherbedarf aus?
3. Weiterführende Überlegungen zu Variablen und Parametern
3.1 Call by value vs. call by reference
Wenn man an die Deklaration von Variablen denkt, so stellt man sich intuitiv eine Tabelle vor, in welcher der entsprechende Name der Variable an ihren Wert gebunden ist:
a = 10 b = 13.2 name1 = "Hans Meier"
| Variablenname | Wert |
|---|---|
| a | 10 |
| b | 13.2 |
| name1 | „Hans Meier“ |
Doch dies ist nur die halbe Wahrheit. Betrachte die beiden folgenden Programme und überlege dir, welchen Wert am Schluss b bzw. list2 haben. Führe die Befehle dann z.B. in Thonny aus. Was stellst du fest? Wie könnte man sich das überraschende Resultat erklären?
a = 3 b = a a = 5 # a ändern print(b)Was denkst du wird am Schluss angezeigt für den Wert von b? Verwenden wir statt ganzer Zahlen eine Liste:
list1 = [1,2,3] list2 = list1 list1.append(20) # die Zahl 20 zur Liste list1 hinzufügen print(list2)
Nun ändern wir den Wert der Variablen list1 anders:
list1 = [1,2,3] list2 = list1 list1 = [100,101] print(list2)
Aufgaben C
- Erkläre den Unterschied, von
call by valueundcall by reference. Hier ist das globale Konzept in der Programmierung gemeint, nicht die konkrete Umsetzung in Python. - Was bedeutet es, wenn eine Variable mutable bzw. immutable ist. Welche Variablentypen sind in Python mutable bzw. immutable?
- „In Python sind alle Variablen Objekte (d.h. Referenztypen) und wenn sie als Parameter einer Funktion übergeben werden, wird ihre Referenz by value übertragen.“ Erkläre diese Aussage.
3.1.1 Call by value
Call by value bedeutet, dass der Wert der Variablen verwendet wird, wenn man diese aufruft, oder als Parameter einer Funktion übergibt. Ruft man also eine Funktion auf, so wird der Wert des Argumentes übergeben:
my_number = 5 def add_one(number): number = number + 1 add_one(my_number) # der WERT von my_number wird übergeben print(my_number)Im Programm von oben, wird
add_one mit dem Parameter my_number aufgerufen. Da dieser Aufruf by Value, d.h. über den Wert erfolgt, wird der Wert von my_number (also 5) als Argument übergeben und an den Parameter number gebunden. Wenn man dann diese Variable number um 1 vergrössert. Hat dies keinen Einfluss auf die Variable my_number: sie verbleibt auf dem Wert 5.
3.1.2 Call by reference
Beim Konzept call by reference wird nicht der Wert der Variablen gespeichert oder übergeben, sondern ihre Referenz , d.h. ihr Ort im Speicher. Wenn man in Python id(<Variablenname>) aufruft, dann erhält man eine Zahl, welche für die Adresse der Variablen im Speicher steht. Man muss sich dann die Variablen so vorstellen:
list1 = [1,2,3] list2 = list1
| Variablenname | Adresse | Wert an der Adresse |
|---|---|---|
| list1 | 0x1f34 | [1,2,3] |
| list2 | 0x1f34 | [1,2,3] |
Da in der Variablen list1 die Referenz (d.h. die Adresse) gespeichert ist und diese dann auf die Liste list2 übertragen wird, zeigen beide auf denselben Ort im Speicher. Wird nun die Liste list1 geändert durch list1.append(20), dann wird die Liste an dieser Adresse geändert und beide Variablen (list1 und list2) zeigen auf diese neue Liste [1,2,3,20].
Wenn man Parameter als Referenz übergibt, dann ändern sich übergebenen Variablen, wenn man diese in einer Funktion ändert. Das folgende ist ein theoretisches Beispiel (in Python ist dies so nicht möglich, siehe die Erklärung unten):
my_number = 5 def add_one(byRef number): # theoretisches Beispiel: Referenz von number wird übergeben number = number + 1 add_one(my_number) # Referenz (Adresse) von my_number wird übergeben. print(my_number) # my_number wäre nun um 1 vergrössert worden, also auf 6.
Würde der Parameter über die Referenz übergeben, würde im obigen Beispiel die Variable my_number auf 6 geändert.
3.3 Wie sieht es in Python aus? "Call by Object Reference"
In vielen Programmiersprachen werden die Grunddatentypen (Integer, Float, Boolean, String) byValue gespeichert und übergeben und die komplexeren Datentypen (Arrays, Objekte, Dictionaries) als Referenz. Nicht so in Python. Alle Variablen sind Objekte und demensprechend Referenztypen (d.h. die Referenz wird gespeichert). Aber die primitiven Datentypen (alle Zahltypen, Boolean, Strings, Tuples) sind immutable, d.h. man kann sie nicht ändern sondern nur durch ein neues Objekt überschreiben. Komplexere Datentypen (z.B. Listen, Dictionaries, eigene Objekte) sind mutable, d.h. man kann sie direkt an ihrem Speicherort ändern. Es folgen die drei Beispielprogramme von oben mit der entsprechenden Erklärung für Python:
Wenn die Variable immutable ist, verhält sich Python wie Call by Value
a = 3 # in a wird die Referenz zum Integer-Objekt 3 gespeichert b = a # b zeigt auf die Adresse desselben Integer-Objekts mit der Zahl 3 a = 5 # da a immutable ist, wird ein neues Integerobjekt erstellt und a zeigt auf dessen Adresse print(b) # b zeigt immer noch auf die Adresse des Integerobjektes mit der Zahl 3
Wenn die Variable mutable ist, verhält sich Python wie Call by Reference
list1 = [1,2,3] # in list1 die Adresse zur Liste [1,2,3] speichern list2 = list1 # list2 zeigt auf dieselbe Adresse wie list1 list1.append(20) # list1 ist mutable und wird an Ort wird list1 zu [1,2,3,20] geändert print(list2) # list2 zeigt auf dieselbe Adresse wie list1, d.h. list2 ist auch [1,2,3,20]
Wenn ein neues Objekt mit einer neuen Adresse erstellt wird:
list1 = [1,2,3] # in list1 die Adresse zur Liste [1,2,3] speichern list2 = list1 # list2 zeigt auf dieselbe Adresse wie list1 list1 = [100,101] # list1 wird nicht an Ort geändert. Ein neues Listenobjekt mit neuer Adresse wird erstellt. print(list2) # list2 zeigt immer noch auf die Adresse in der [1,2,3] steht
Aufgabe D
- Betrachte das untenstehende Programm und erkläre Zeile für Zeile, was genau geschieht.
- Was wird am Schluss in l1 bzw. l2 stehen?
def change_value(list1, list2):
list1[2] = 5
list2 = [6, 10]
l1 = [1,2,3,4]
l2 = [10,11,12]
change_value(l1,l2)
print(l1)
print(l2)
3. Listen (Arrays) erstellen, durchgehen und der range-Befehl
3.1 Listen erstellen
Mit eckigen Klammern kann man in Python eine Liste erstellen. Dabei können die einzelnen Elemente der Liste ganz unterschiedliche Typen haben. Es können sogar selbst wieder Listen sein. Auf die einzelnen Elemente der Liste kann man zugreifen, indem man den Namen der Liste mit eckigen Klammern und dem Index angibt (der Index bezeichnet die Position des Elementes in der Liste - er beginnt bei 0. Gibt man als Index negative Zahlen an, so zählt Python vom letzten Element an rückwärts. D.h. das letzte Element der Liste Liste1 erhält man mit Liste1[-1]
>>> Liste1 = [1, 2, 3, 4, 5] >>> Liste2 = [51, "Hallo", True, 3.141592] >>> Liste1[1] 2 >>> Liste2[-1] 3.141592 >>>
Listen verwendet man oft, wenn man viele Daten speichern muss. Statt dass man z.B. zehn Variablen v1=5, v2=3, v3=8, v4=9,…, v10=0.34 definiert, erstellt man besser eine Liste 'v = [5,3,8,9,…,0.34]' und greift dann auf die Werte zu, indem man v[0], v[1] etc. aufruft.
Aufgabe E
Gegeben ist eine Liste von Baumaterialien: Materialien=[RED_SANDSTONE, GRASS, WOOL, DIAMOND_BLOCK, GOLD_BLOCK]
Schreibe ein Programm, welches den Agenten dazu bringt, eine Linie mit fünf verschieden Blöcken aus den Materialien der Liste zu bauen. Die Reihenfolge der Liste soll dabei eingehalten werden.
Tipps:
- Dein Code beginnt mit
Materialien=[RED_SANDSTONE, GRASS, WOOL, DIAMOND_BLOCK, GOLD_BLOCK] - Die Liste muss in deinem Code verwendet werden
- Dein Programm muss zunächst das Inventar des Agenten mit den richtigen Materialien füllen.
3.2 Der range-Befehl
Sehr häufig möchte man eine regelmässige Liste von Zahlen erstellen: z.B. alle Zahlen von 1 bis 10 oder die Zahlen von 1 bis 100 in 2er-Schritten etc. Dazu ist der range-Befehl sehr praktisch: Er erstellt eine Liste von einem Startwert bis zu einem Endwert mit einer bestimmten Schrittweite:
| range-Befehl | Bedeutung |
|---|---|
range(10) | Liste der Zahlen von 0 bis 10 (exklusive 10), also [0,1,2,3,4,5,6,7,8,9] |
range(4,9) | Liste der Zahlen von 4 (inkl.) bis 9 (exkl.), also [4,5,6,7,8] |
range(13,25,3) | Liste der Zahlen von 13 (inkl.) bis 25 (exkl.) in 3er-Schritten, also [13,16,19,22] |
Aufgabe F
Erstelle mit dem range-Befehl die folgenden Listen:
L1die Liste der ganzen Zahlen zwischen 0 und 8.L2die Liste der ganzen Zahlen, die kleiner als 20 und durch 3 teilbar sind.L3die Liste der ganzen Zahlen zwischen 20 und 40, die durch 4 teilbar sind.
Tipp: Mit dem Befehl player.say kannst du deine Listen anzeigen lassen. Beispiel: player.say(L1)
3.3 Listen durchgehen
Ganz oft will man für alle Elemente in einer Liste dasselbe tun, d.h. man will die Liste „abklappern“ (durchgehen) und dann für jedes Element dieselbe Aktion durchfühen. Z.B. hat man eine Liste von Positionen und möchte bei jeder Position ein Haus bauen, oder man hat eine Liste von Baumaterialien und man möchte für jedes dieser Materialien einen Block platzieren etc.
Dafür gibt es in Python den Befehl for <Variable> in <Liste>. Am besten versteht man dies an einem Beispiel. Wir verbessern unser Programm, welches die Spirale baut, weiter:
def baueSpirale(richtung):
agent.move(FORWARD,1)
agent.turn(richtung)
agent.move(FORWARD,2)
agent.turn(richtung)
agent.move(FORWARD,3)
agent.turn(richtung)
agent.move(FORWARD,4)
agent.turn(richtung)
agent.move(FORWARD,5)
agent.turn(richtung)
agent.move(FORWARD,6)
Wir sagen Python einfach: Gehe alle Zahlen von 1 bis 6 durch (sage der Variablen z.B. zahl) und mache dann die beiden Befehle:
agent.move(FORWARD,zahl)
agent.turn(richtung)
</code>
Damit sieht unser Programm viel kürzer aus:
<sxh python;title:Bessere Version mit Schleife>
def baueSpirale(richtung):
for zahl in [1,2,3,4,5,6]:
agent.move(FORWARD,zahl)
agent.turn(richtung)
Die Liste [1,2,3,4,5,6] können wir uns natürlich auch mit dem Range-Befehl erstellen lassen:
def baueSpirale(richtung):
for zahl in range(1,7):
agent.move(FORWARD,zahl)
agent.turn(richtung)
for i in range(10) verwenden.
for i in range(10): # i geht die Zahlen von 0 bis 9 durch agent.move(FORWARD,2) agent.place(BACK)
Weitere Listenbefehle
| Listenbefehl | Bedeutung |
|---|---|
L1 = [3, „bla“, 5, 6] | Liste erstellen |
L1[1] | Auf das erste Element zugreifen (Achtung: Zählung beginnt bei 0!) |
len(L1) | Länge der Liste L1 (Anzahl der Elemente) |
[3,6]+[1,9] oder [3,6].extend([1,9]) | Listen zusammenfügen |
L1.append(3) | Element am Schluss der Liste anfügen |
del L1[0] | Ein Element bei einem bestimmten Index löschen |
L1.remove(„bla“) | Ein Element mit einem bestimmten Wert löschen |
L1[1:3] | Unterliste von Index 1 (inkl.) bis Index 3 (exkl.) |
L1[1:] | Unterliste von Index 1 (inkl.) bis zum Schluss der Liste |
3 in L1 | Testet, ob der Wert 3 in der Liste L1 enthalten ist. Gibt True oder False zurück. |
Aufgaben G
- Schreibe eine Funktion
LinieDuo(n), welche eine Linie mit zwei selbst gewählten Materialien baut, wobei es jeweils abwechselt. - Schreibe eine Funktion
LinieTre(n), welche eine Linie mit drei selbst gewählten Materialien baut, wobei es jeweils abwechselt mit allen drei Materialien. - Schreibe eine Funktion
LinieDoppelt(n), welche eine Linie mit Höhe zwei Blöcke und Länge n baut. Das Baumaterial ist frei wählbar. - Schreibe eine Funktion
LinieMitHöhe(n,h), welche eine Linie mit Höhe zwei Blöcke und Länge n und Höhe h baut. - Schreibe eine Funktion
quadrat(n), welche den Agenten dazu bringt, ein nicht ausgefülltes Quadrat der Länge n zu bauen. - Schreibe eine Funktion
quadratf(n)welche ein gefülltes Quadrat baut. - Schreibe eine Funktion
tower(n,h)welche einen Turm mit quadratischer Grundfläche der Breite n und der Höhe h baut.
4. Verzweigungen mit ''if'' und Schleifen mit ''while''
Verzweigungen mit if
Mit der if Anweisung kann man Befehle nur dann ausführen lassen, wenn eine bestimmte Bedingung wahr (True) ist.
if (agent.get_item_count(1)>0): # wenn noch Material im Fach 1 liegt
agent.set_slot(1) # Das aktuelle Fach auf 1 setzen
Man kann mit dem if-Befehl auch mehrere Bedingungen prüfen (elif) und am Schluss etwas ausführen, wenn keine Bedingung zutrifft (else):
if (agent.get_item_count(1)>0): # wenn Material im Fach 1 liegt
agent.set_slot(1) # Fach 1 als aktuelles Fach setzen
elif (agent.get_item_count(2)>0): # sonst: wenn Material in Fach 2 liegt
agent.set_slot(2) # Fach2 als aktuelles Fach setzen
else: # sost
player.say("Ich habe nichts im Fach 1 oder 2!") # den Spieler sagen lassen, dass nichts im Inventarslot 1 oder 2 liegt.
Schleifen mit "while"
Wir haben bereits die for-Schleife gesehen, um Befehle zu wiederholen. Mit der while-Schleife kann man das auch tun, wobei die Wiederholung nicht durch eine Liste gesteuert ist (wie bei der for-Schleife) sondern durch eine Bedingung. Solange die Bedinugung wahr (True) ist, werden die Befehle wiederholt (das folgende Beispiel funktioniert im Kreativ-Modus nicht, da dort die Anzahl der Materialien nicht abnimmt):
while agent.inspect(AgentInspection.BLOCK, FORWARD)==AIR: # solange AIR vor ihm ist
agent.move(FORWARD, 1)
while agent.detect(AgentDetection.BLOCK, FORWARD): # solange ein Block for ihm ist
agent.turn_left()
Aufgaben E
- Erstelle eine Funktion
linie(n, material), welche eine Linie der Länge n mit dem übergebenen Material erstellt. - Erstelle eine Funktion
linie2(n, material1, material2), welche eine Linie der Länge n mit abwechselnden Materialienmaterial1undmaterial2macht. - Erstelle eine Funktion
rechteck(n,m,material)welche ein Rechteck der Länge n und Breite m baut mit dem Materialmaterial - Erstelle eine Funktion
schachbrett(n,m,mat1,mat2), welche ein Schachbrett der Länge n und Breite m macht mit den Materialienmat1undmat2 - Erstelle eine Funktion
scan(), welche den Bereich (0,-60,0) bis (20,-60,20) abklappert, alle gefundenen Blöcke zerstört und speichert und dann dasselbe an der Position (100,-60,0) bis (100,-60,20) baut. - Schreibe eine Funktion
kugel(n), welche eine Kugel baut mit „Radius“ n, ohne dabei die Funktion shapes.sphere vom Code-Builder zu nutzen. - Schreibe eine Funktion
house(), welche ein Haus baut.Siehe dabei auch den Tipp unten!