Einfuhrung in RUBYKARA
Gerhard Bitsch∗
Kepler-Gymnasium Tubingen
24. August 2008
1 Die RUBYKARA -Umgebung
Die ProgrammierumgebungRUBYKARA erlaubt es, Kara mitder Programmiersprache RUBY
zu steuern.Dazu stellt RUBYKARA einenkleinen Programmeditor zurVerfugung, der beim Aufruf ei-nige Programmierhinweise undein einfaches Programm enthalt.Befehle fur KARA mussen miteinem vorgestellten kara. ge-schrieben werden, also etwakara.move, um KARA ein Feldnach vorn zu bewegen.Dieses Programm ist unmittel-bar ausfuhrbar. Man muss ledig-lich den entsprechenden Knopfin der KARA -Welt betatigen.
Der grun gefarbte untere Teil des Programmfensters dient zur Ausgabe von Fehlermeldungen.
Das im Bild dargestellte Programm zeigt schon einige Besonderheiten der Programmierungmit RUBY im Gegensatz zum Automatenmodell.
Der grau dargestellte obere Fensterteil enthalt Kommentare, die einige der zur Verfugung ste-henden Befehle darstellen. Ein Kommentar beginnt mit dem Zeichen #. Kommentare werdenvom Programm wahrend des Ablaufs ignoriert. Sie sollen lediglich die Verstandlichkeit vonCode verbessern.
Das im Beispiel angezeigte Programm lasst KARA bis zum nachsten Baum laufen und dortstehen bleiben.
∗mailto:[email protected]
1
Das Bild zeigt ein Automatenprogramm mitder gleichen Wirkung. Die Anweisung, dassKARA , wenn er vor keinem Baum steht, einenSchritt machen soll und dann im ZustandFindeBaum bleiben soll, wird mit der while-Anweisung ubertragen (while ' solange). DerSchrittbefehl ist kara.move.
Mit kara.treeFront wird der Sensor abgefragt. Diese Abfrage liefert true, falls KARA voreinem Baum steht und false andernfalls. Der Operator not steht fur die Negation, d.h. ervertauscht die Werte true und false.
2 Einfache Anweisungen in RUBY
In diesem Abschnitt werden einfache RUBY -Anweisungen zur Strukturierung von Program-men vorgestellt. RUBY ist eine objektorientierte Sprache, die nicht kompiliert, sondern inter-pretiert wird. Das bedeutet, dass jeder Ausdruck in einem Programm unmittelbar vor derAusfuhrung in Anweisungen fur den Rechner ubersetzt wird. Das hat den Vorteil, dass manauch einzelne Anweisungen direkt austesten kann. Der Nachteil solcher Programme besteht inihrem gegenuber kompilierten Programmen deutlich langsameren Ablauf.
Die Objektorientierung hat in RUBY zur Folge, dass selbst Zahlen als Objekte definiert sind, diegewisse Methoden zur Verfugung stellen.
Bedingungen: Beim Automatenmodell wird ein unterschiedliches Verhalten von KARA durch die Zu-stande der Sensoren gesteuert. In RUBY kann man diese Sensoren abfragen. Sie lieferndabei einen der Werte true oder false . Ausdrucke mit der Eigenschaft, einen dieser Wertezu liefern, nennt man Bedingungen.
Bedingungen konnen mit aussagenlogischen Operatoren verknupft werden. Die folgen-de Tabelle gibt das Ergebnis einer solchen Verknupfung fur zwei Bedingungen a und bwieder:
a b not a a and b a or bnicht und oder
true true false true truetrue false false false truefalse true true false truefalse false true false false
An Stelle von not kann man auch !, fur and auch && und fur or auch || verwenden.
Beispiele:
not kara.onLeaf hat den Wert true , falls KARA auf einem leeren Feld steht.
kara.treeLeft and kara.treeRight hat den Wert true , falls links und rechts vonKARA ein Baum steht.
kara.treeFront or kara.onLeaf hat den Wert true , falls mindestens eine der beidenBedingungen zutrifft.
while: Die while-Schleife, die schon im vorigen Abschnitt angesprochen wurde, hat folgendeGestalt:
2
while Bedingung
Anweisung1
... Diese Anweisungen bilden einen Block
Anweisungn
end
Bei der Ausfuhrung einer while-Anweisung wird zunachst die Bedingung uberpruft.Liefert sie den Wert true , so werden die Anweisungen (jeweils durch einen Zeilenwechselabgeschlossen) nacheinander ausgefuhrt. Anschließend beginnt der Vorgang mit der Uber-prufung der Bedingung neu. Dies wird so lange wiederholt, bis die Bedingung den Wertfalse liefert.
Verzweigung: Verzweigungen entstehen, wenn je nach dem Wert einer Bedingung unterschiedliche An-weisungen ausgefuhrt werden. Die allgemeine Form ist:
if Bedingung
Anweisungen falls true
else
Anweisungen falls false
end
Beispiel:
1 i f kara . onLeaf // f a l l s Kara auf einem B l a t t s t e h t2 kara . removeLeaf // B l a t t ent fernen3 e lse // a n d e r n f a l l s4 kara . putLeaf // B l a t t ablegen5 end
Soll keine Anweisung ausgefuhrt werden, wenn die Bedingung nicht erfullt ist, so kannman den else-Teil der Anweisung weglassen.
Beispiel:
1 i f kara . t r e e F r o n t // f a l l s Kara vor einem Baum s t e h t2 kara . t u r n L e f t // nach l i n k s drehen3 end // ansonsten n i c h t s tun ,4 // Programm f o r t s e t z e n
Methoden: Man kann auch eigenen Methoden definieren, die dann wie die in der Umgebung vor-handenen Methoden verwendet werden konnen. Es gibt dafur mehrere Moglichkeiten,die einfachste fuhren wir jetzt ein.
def Methodenname(Parameter)
Anweisungen
end
Der zwischen def und end eingeschlossene Programmtext wird bei der Ausfuhrung desProgramms zunachst nicht durchgefuhrt, sondern nur als Methode ”registriert“, die imweiteren Programm verwendet werden kann. Beim Aufruf der Methode muss fur ihre Pa-rameter jeweils ein Objekt ubergeben werden, das im Text der Methode fur den entspre-chenden Parameter eingesetzt wird. Danach erst wird die Methode durchgefuhrt. Dies ist
3
vergleichbar zur Definition einer Funktion in der Mathematik in der Form f(x) = ...x...,bei der zur Berechnung bestimmter Funktionswerte fur x ein Wert eingesetzt wird, mitdem dann die rechte Seite der Definition ausgewertet wird.
Beispiel: KARA soll zum nachsten Baum gehen, sich dort umdrehen und weiter laufenund dies endlos wiederholen.
1 @kara=kara2 def drehen3 2 . t imes {@kara . t u r n L e f t }4 end5
6 while true7 drehen i f kara . t r e e F r o n t8 kara . move9 end
Das Programm muss gespeichert werden, ehe man es starten kann.
KARA ist (momentan) fur Methoden nicht verfugbar. Mit der ersten Zeile @kara=karawird KARA an die globale Variable @kara gebunden und kann auch von Methoden ver-wendet werden. Man sollte diese Zuweisung immer an den Anfang einer neuen Pro-grammdatei stellen.
Die Methode times wiederholt den durch geschweifte Klammern abgetrennten Block sooft, wie die ganze Zahl, fur die times aufgerufen wurde angibt.
Eine weitere Besonderheit ist die Verwendung von if in der while-Schleife als Modifika-tor. Der vor if stehende Ausdruck wird nur ausgewertet, wenn die hinter if stehendeBedingung erfullt ist.
Die Schleife lauft endlos, weil die hinter while stehende Schleifenbedingung nie falschwerden kann.
3 Struktogramme
Struktogramme ermoglichen es, den Ablauf eines Programms graphisch zu entwerfen. Das gan-ze Programm wird in einem Rechteck eingetragen. Schleifen, Fallunterscheidungen und Me-thodenaufrufe (fur selbstgeschriebene Methoden) werden wie folgt dargestellt:
• while-SchleifenSchleifenbedingung
Ausdruck1
· · ·Ausdruckn
4
• FallunterscheidungenPPPPPPPPPPP
�����������
Bedingung
T FTrue-Teil False-Teil
• MethodenaufrufeMethode
Beispiel:
Hier ist ein einfaches Beispiel fur ein Struktogramm zu einem RUBYKARA -Programm. KARA
soll zum nachsten Baum laufen und unterwegs alle Felder invertieren, d.h. auf Feldern mit Blattdas Blatt wegnehmen und auf Feldern ohne Blatt ein Blatt ablegen.
ZumBauminvertiereFeld
not treeFrontmove
invertiereFeld
In diesem Struktogramm wird eine Anweisung verwendet, die KARA nicht kennt: invertiereFeld.Diese Anweisung wird als Methode implementiert. Das zugehorige Struktogramm ist:
invertiereFeld()PPPPPPPPPPP
�����������
onLeaf
T FremoveLeaf putLeaf
Diese Struktogramme ubersetzen sich in folgendes RUBYKARA -Programm:
1 @kara=kara2 def i n v e r t i e r e F e l d3 i f @kara . onLeaf4 @kara . removeLeaf5 e lse6 @kara . putLeaf7 end8 end9
10 i n v e r t i e r e F e l d11 while ! kara . t r e e F r o n t
5
12 kara . move13 i n v e r t i e r e F e l d14 end
4 Variablen
Aufgabe: KARA soll zu einem Baum laufen, sich umdrehen und dann weiter laufen. Das soller funf mal wiederholen.
Im Automatenmodell wurden fur diese Aufgabe funf Zustande benotigt. Andert man die An-zahl der Wiederholungen, so andert sich die Anzahl der benotigten Zustande entsprechend. Esgibt im Automatenmodell keine einfache Moglichkeit, beliebig weit zu zahlen.
In RUBYKARA kann man zahlen, indem man Variablen verwendet. Variablen bieten eine Mog-lichkeit, Daten im Speicher des Rechners abzulegen und zu verandern. Dazu muss man sichden Speicherort merken, um auf die gespeicherten Daten zugreifen zu konnen. Zu diesemZweck werden Variablen verwendet. In RUBY erfolgt das durch die Angabe eines Namens undeines Anfangswertes:
zahler = 0
Diese Anweisung erzeugt eine Variable zahler und speichert 0 als Wert dieser Variablen.
Wenn man sich ein Gedankenmodell fur Variable machen will, kann man sich folgendes vorstel-len: mit einer Deklaration einer Variablen wird eine Schachtel passender Große angefertigt undmit einem Namensschild versehen. Ist ein Anfangswert angegeben, so wird dieser auf einenZettel geschrieben und der Zettel in die Schachtel gelegt. Die Schachtel kommt in ein Lager,wo sie uber den aufgeklebten Namen wieder gefunden werden kann.
Nun soll mit Hilfe einer Variablen das anfangs gestellte Problem gelost werden. Zunachst einStruktogramm:
FunfRundenint runden← 0
runden < 5hhhhhhhhhhhhhhhh
������
treeFrontW F
drehenrunden← runden + 1
move
Die Zuweisung eines Wertes zu einer Variablen symbolisiert man im Struktogramm durcheinen linksgerichteten Pfeil ←. Besonders interessant ist dabei die Zuweisung in der Fallun-terscheidung. Sie zeigt an, dass der Variable runden ihr um 1 erhohter alter Wert zugewiesenwerden soll. Da dies jedesmal geschieht, wenn KARA vor einem Baum steht, zahlt diese Va-riable die von KARA zuruckgelegten Runden. Nach 5 Runden hat die Variable den Wert 5, dieSchleifenbedingung ist also nicht mehr erfullt und KARA bleibt stehen.
Im zugehorige RUBYKARA -Programm wird die Zuweisung von Werten an die Variable rundenmit dem Gleichheitszeichen = geschrieben. Diese Verwendung entspricht naturlich nicht demGebrauch von = in der Mathematik, ist aber in vielen Programmiersprachen ublich. Fur Ver-gleiche von Zahlen kann man mit <, >, == Bedingungen formulieren (das doppelte Gleich-heitszeichen uberpruft die Gleichheit zweier Zahlen).
6
1 z ah ler = 02
3 while z ah ler < 54 i f kara . t r e e F r o n t5 2 . t imes {kara . t u r n L e f t }6 z ah ler = z ah ler + 17 e lse8 kara . move9 end
10 end
AufgabenFertigen Sie fur die folgenden Aufgaben jeweils ein Struktogramm an, ehe Sie versuchen dasProgramm zu erstellen. verwenden Sie wo moglich eigene Methoden.
1. Bearbeiten Sie die Aufgabe Tunnelsucher II und die drei Aufgaben zur Kleeblattsuche imWald.
2. Bearbeiten Sie die Aufgabe Pacman.
3. KARA soll ein 4× 5-Rechteck mit Blattern belegen.
4. KARA soll ein Schachbrett (8×8) auslegen (weisse Felder leer, schwarze Felder mit Blatt).
LosungenAufgabe 1:
Tunnelsucher:
Den zwei benotigten Zustanden fur dieses Problem im Automatenmodell entsprechen hierzwei while-Schleifen.TunnelEnde
not(treeLeft and treeRight)move
treeLeft and treeRightmove
Das zugehorige Programm:
1 kara . move while not ( kara . t r e e L e f t and kara . t r e e R i g h t )2 kara . move while kara . t r e e L e f t and kara . t r e e R i g h t
Wald I
Das Struktogramm verwendet die Methode umBaum, die noch definiert werden muss.
Wald Inot onLeafXXXXXXXXXXX
�����������
treeFrontT F
umBaum moveremoveLeaf
7
Das zugehorige Programm:
1 @kara=kara2 def umBaum3 @kara . t u r n L e f t4 @kara . move5 @kara . turnRight6 2 . t imes {@kara . move}7 @kara . turnRight8 @kara . move9 @kara . t u r n L e f t
10 end11
12 while not kara . onLeaf13 i f kara . t r e e F r o n t14 umBaum15 e lse16 kara . move17 end18 end19 kara . removeLeaf
Wald II
Hier muss lediglich die Methode umBaum angepasst werden. Der mittlere Teil mit den zweimove-Befehlen muss ersetzt werden durch eine Schleife, um beliebig viele Baume zu umgehen:
1 def umBaum2 @kara . t u r n L e f t3 @kara . move4 @kara . turnRight5 @kara . move6 @kara . move while @kara . t r e e R i g h t7 @kara . turnRight8 @kara . move9 @kara . t u r n L e f t
10 end
Wald III
Hier wird eine Unterscheidung von drei verschiedenen Fallen benotigt: Baum vorn, Baum linksund Baum rechts. Man erledigt das mit einer geschachtelten Fallunterscheidung. Man pruftzunachst, ob vorn ein Baum steht. Ist dies nicht der Fall, pruft man, ob rechts oder links einBaum steht.
Man erhalt folgendes Struktogramm:
8
Wald3not onLeaf
PPPPPPPPPPPPPPPPPPPPP
��
���
��
treeFront
T FPPPPPPPPPPP
�����������
not treeLeft
T FturnLeft turnRight
∅
moveremoveLeaf
Dies fuhrt zu folgendem Programm. Die geschachtelte Fallunterscheidung wird aus dem Struk-togramm so ubertragen, dass innerhalb der ersten Fallunterscheidung eine zweite eingefugtwird. Dies lasst sich beliebig oft wiederholen.
1 while not kara . onLeaf2 i f kara . t r e e F r o n t3 i f not kara . t r e e L e f t4 kara . t u r n L e f t5 e lse6 kara . turnRight7 end8 end9 kara . move
10 end11 kara . removeLeaf
Aufgabe 2:
Pacman
Dieses Programm benotigt eine Schleife und innerhalb der Schleife eine geschachtelte Fallun-terscheidung. Im ersten Fall ist nichts zu tun, falls KARA auf einem Blatt ist, im anderen Fallmuss KARA das nachste Blatt erst lokalisieren und sich auf das Feld mit dem Blatt begeben. DieSchleife hat also als Invariante die Bedingung, dass KARA auf einem Blatt stehen muss. Dieseswird am Ende jedes Schleifendurchgangs entfernt.
9
PacmanremoveLeaf
not treeFrontmovehhhhhhhhhhhhhhhhhhhhhhhhh
�����
����
not onLeaf
T F
zuruckturnRight
movehhhhhhhhhhhhhhhhhhh
�������
not onLeafT F
zuruckmove ∅
∅
removeLeaf
Um KARA auf das nachste Blatt zu bewegen wird die Methode zuruck verwendet. Das benotig-te Struktogramm fur die Methode zuruck ist:
zuruckturnLeft()turnLeft()
move()
Daraus erhalt man das folgende Programm:
1 @kara=kara2 def zuruck # u m d r e h e n u n d z u r u c k
3 2 . t imes {@kara . t u r n L e f t }4 @kara . move5 end6
7 kara . removeLeaf8 while not kara . t r e e F r o n t9 kara . move
10 i f not kara . onLeaf # k e i n B l a t t v o r n
11 zuruck12 kara . turnRight13 kara . move14 i f not kara . onLeaf # n i c h t s l i n k s
15 zuruck16 kara . move # n a c h r e c h t s !
17 end18 end19 kara . removeLeaf # h i e r m u s s w a s l i e g e n
20 end
10
Aufgabe 3:
Fur das Rechteck erhalt man zunachst eine Programmstruktur mit zwei ineinander geschach-telten Schleifen. Eine außere Schleife ist fur die aufeinanderfolgende Anordnung der Reihendes Rechtecks zustandig, in einer inneren Schleife wird jeweils eine einzelne Reihe ausgege-ben.
Rechteck4 mal
reiheLegen()nachsteReihe()
Das Legen einer Reihe wird als Methode formuliert und mit einer Schleife realisiert:
reiheLegen
5 malputLeaf()move()
nachsteReihe()2 mal turnLeft()
5 malmove()
turnLeft()move()
turnLeft()
Der Wechsel zur nachsten Reihe ist ebenfalls als Methode realisiert. KARA geht zum Anfang dervorigen Reihe und wechselt dann in die zu legende neue Reihe. Das scheint umstandlich, aberfur abwechselnde Links- und Rechtsdurchgange benotigt man jetzt noch nicht besprocheneHilfsmittel. Das folgende Programm zeichnet das gewunschte Rechteck.
1 @kara=kara2 def reiheLegen3 5 . t imes do4 @kara . putLeaf5 @kara . move6 end7 end8
9 def nachsteReihe10 2 . t imes {@kara . t u r n L e f t }11 5 . t imes {@kara . move}12 @kara . t u r n L e f t13 @kara . move14 @kara . t u r n L e f t15 end16
17 4 . t imes do18 reiheLegen19 nachsteReihe20 end
Aufgabe 4
11
Diese Aufgabe ist eine Variante des Rechteck-Problems. Allerdings mussen zwei aufeinanderfolgende Reihen um eins gegeneinander versetzt gelegt werden. Die folgenden Struktogrammebeschreiben eine mogliche Losung.
Schachbrett4 mal
reiheLegen1()nachsteReihe()reiheLegen2()nachsteReihe()
Die Methoden reiheLegen1() und reiheLegen2 unterscheiden sich nur geringfugig.
reiheLegen1
4 malputLeaf
2 mal move
reiheLegen2
4 malmove
putLeafmove
Die Methode nachsteReihe() wird durch folgendes Struktogramm beschrieben:
nachsteReihe()2 mal turnLeft
8 mal moveturnLeft
moveturnLeft
Das fertige Programm sieht dann so aus:
1 @kara=kara2 def reiheLegen13 4 . t imes do4 @kara . putLeaf5 2 . t imes {@kara . move}6 end7 end8
9 def reiheLegen210 4 . t imes do11 @kara . move12 @kara . putLeaf13 @kara . move14 end15 end16
17 def nachsteReihe18 2 . t imes {@kara . t u r n L e f t }19 8 . t imes {@kara . move}20 @kara . t u r n L e f t
12
21 @kara . move22 @kara . t u r n L e f t23 end24
25 # H a u p t p r o g r a m m
26 4 . t imes do27 reiheLegen128 nachsteReihe29 reiheLegen230 nachsteReihe31 end
5 Methoden mit Parametern und Ruckgabewerten, Eingaben undAusgaben
Haufig will man einer Methode beim Aufruf Informationen ubergeben, die den Ablauf derMethode beeinflussen konnen. Bisher wurde nur das Objekt kara an Methoden ubergeben. Oftwill man aber weitere Informationen zur Steuerung der Methode ubergeben.
Als erstes Beispiel soll das erlautern. Es soll eine Methode reiheLegen(n) vorgestellt werden,die KARA veranlasst, n Schritte zu gehen und dabei auf nicht belegten Feldern ein Blatt abzu-legen.
1 def reiheLegen ( n )2 n . t imes do3 @kara . putLeaf i f not @kara . onLeaf4 @kara . move5 end6 end
Ruft man diese Methode beispielsweise mit reiheLegen(7) auf, so bewegt sich KARA 7 Felderin seiner gegenwartigen Richtung und belegt alle leeren Felder, die er passiert mit einem Blatt.Das letzte Feld, auf dem KARA stehen bleibt, wird nicht belegt. Das Ausgangsfeld hingegenwird belegt.
Im Unterschied zu den bisherigen Definitionen von Methoden steht hier in der Klammer hinterdem Methodennamen ein Parameter.
Beim Aufruf einer Methode mit Parametern mussen in die Klammern hinter dem Methoden-namen Ausdrucke fur die Parameter eingetragen werden (durch Kommata getrennt, falls esmehrere Parameter gibt). Rechenausdrucke sind bei der Parameterubergabe erlaubt.
Aufgaben:
1.1 def reiheLegen ( n )2 n . times do3 @kara . move4 @kara . putLeaf i f not @kara . onLeaf5 end6 end
Was andert sich bei der MethodereiheLegen(n), wenn sie wie ne-ben stehend formuliert wird?
13
2. Schreiben Sie eine Methode turnLeft(int anzahl) und eine Methode turnRight(intanzahl), die KARA veranlasst, sich so oft nach links bzw. rechts zu drehen, wie anzahlangibt. Programmieren Sie ein passendes Verhalten fur negative Werte von anzahl.
3. Verandern Sie das Schachbrettprogramm (Seite 7) so, dass nur eine Methode zum Legender Reihen benotigt wird und die Große des Schachbretts variabel gehalten wird.
In vielen Fallen mochte man erst zur Laufzeit Daten eingeben konnen. Dazu stellt RUBYKARA
unter anderen (Seite 18) die Methode intInput(Titel) zur Verfugung. Diese Methode wirdnun verwendet, um das Rechteck-Programm zu verallgemeinern. intInput benotigt als Pa-rameter eine Eingabeaufforderung in Form eines Strings (Zeichenkette). Strings werden ein-gegeben, indem man den gewunschten Text in Anfuhrungszeichen einschließt. Außerdem hatdie Methode eine ganze Zahl als Ruckgabewert. Dazu wird durch die Methode ein Fenster mitdem Text als Eingabeaufforderung und einem Eingabefeld geoffnet. In dieses Feld wird diegewunschte Zahl eingegeben.
Man kann deshalb Anweisungen wie
anzahl = tools.intInput("Geben Sie eine Anzahl an!")
schreiben. Dabei wird beim Lauf des Programms ein Fenster geoffnet und die dort eingegebeneZahl der Variablen anzahl zugewiesen. Fur das Rechteckprogramm benotigt man nur kleineAnderungen:
1 @kara=kara2 def reiheLegen ( n )3 n . t imes do4 @kara . putLeaf5 @kara . move6 end7 end8
9 def nachsteReihe ( n )10 2 . t imes {@kara . t u r n L e f t }11 n . t imes {@kara . move}12 @kara . t u r n L e f t13 @kara . move14 @kara . t u r n L e f t15 end16
17 # H a u p t p r o g r a m m
18 hoehe = t o o l s . i n t I n p u t ( ”Hohe des Rechtecks ? ” )19 b r e i t e = t o o l s . i n t I n p u t ( ” B r e i t e des Rechtecks ? ” )20 hoehe . t imes do21 reiheLegen ( b r e i t e )22 nachsteReihe ( b r e i t e )23 end
KARA soll nun zu einem Baum laufen, die Anzahl der Schritte zahlen, zu seinem Ausgangs-punkt zuruckkehren und die Anzahl der Schritte bis zum Baum ausgeben.
Fur die Ausgabe verwenden wir die Methode (Seite 18) tools.showMessage(String Text).Die Schritte werden in einer Variablen mitgezahlt. Dies fuhrt zu folgendem Programm.
14
1 s c h r i t t e =02 while not kara . t r e e F r o n t3 kara . move4 s c h r i t t e +=15 end6 2 . t imes {kara . t u r n L e f t }7 1 . upto ( s c h r i t t e ) {kara . move}8 2 . t imes {kara . t u r n L e f t }9 t o o l s . showMessage ( ”Zum Baum sind es #{ s c h r i t t e } S c h r i t t e . ” )
Besondere Beachtung verdient die Art, wie hier der Text der Meldung zusammengestellt wird.In RUBY wird Text (Datentyp: String) durch Anfuhrungszeichen begrenzt. Werte von Variablenoder Ausdrucken konnen mit dem Konstrukt #{...} in Text eingefugt werden. RUBY wandeltin diesem Fall die Ausdrucke mit der Methode to s in ihre Textdarstellung um.
Man kann auch Methoden schreiben, die Werte als Ergebnis liefern, das zu weiteren Berechnun-gen verwendet werden kann. In der Methode wird dann mit return Wert ein Wert passendenTypes zuruckgegeben. Dazu ein einfaches Beispiel. Die Methode treeBack? liefert true , fallshinter KARA ein Baum ist.
1 @kara=kara2 def t reeBack ?3 @kara . t u r n L e f t4 erg=@kara . t r e e L e f t5 @kara . turnRight6 return erg7 end
Aufgaben
3. Schreiben Sie eine Methode mushroomLeft? und eine Methode
mushroomRight? und testen Sie diese in geeigneter Umgebung.
6 Schleifen
Bisher sind Schleifen mit nicht vorherbestimmter Anzahl von Wiederholungen mit der while-Anweisung konstruiert worden
1 while Bedingung do2 Anweisung ( en )3 end
Der Anweisungsblock zwischen do und end wird dabei so lange wiederholt ausgefuhrt, wie dieBedingung den Wert true liefert. Es kann also auch vorkommen, dass der Block gar nicht aus-gefuhrt wird, weil die Bedingung schon zu Beginn nicht erfullt ist. Man nennt solche Schleifendeshalb auch abweisende Schleifen oder Schleifen mit Vorbedingung.
Fur Schleifen mit einer festen Anzahl n von Wiederholungen wurde die Iteration
1 n . t imes {Anweisung}
15
oder
1 1 . upto{n} do | i |2 # A n w e i s u n g e n d i e d e n j e w e i l i g e n W e r t v o n i v e r w e n d e n
3 end
verwendet. An Stelle der Konstruktion
while not Bedingung do ... kann man auch
until Bedingung do ... verwenden. Beide Schleifenkonstrukte konnen auch als Modifikato-ren verwendet werden:
Beispiele:
kara.move until kara.treeFront
x=0x=x+1 while x<100
eingabe=-1eingabe=tools.intInput("Zahl eingeben") until (eingabe>0) and (eingabe<100)
ACHTUNG: Die Initialisierung von x und eingabe ist dabei notwendig!
Aufgaben
1. Fertigen Sie fur das folgende Programm ein Struktogramm an und erlautern Sie seineFunktion.
1 @kara = kara2
3 def reiheLegen ( r e c h t s )4 4 . t imes do5 @kara . putLeaf6 2 . t imes {@kara . move}7 end8 i f r e c h t s then9 @kara . turnRight
10 @kara . move11 @kara . turnRight12 @kara . move13 e lse14 @kara . t u r n L e f t15 @kara . move16 @kara . t u r n L e f t17 @kara . move18 end19 end20
21 4 . t imes do22 reiheLegen ( t rue )23 reiheLegen ( f a l s e )24 end
16
2. Schreiben Sie ein Programm, das vom Benutzer die Anzahl der Strecken und die Anzahlder Blatter erfragt, die bei jeder Strecke im Vergleich zur vorigen mehr gelegt werdensollen und dann entsprechend Blatter legt.
3. Schreiben Sie ein Programm das vom Benut-zer die Anzahl der gewunschten Reihen erfragtund dann ein entsprechendes (gefulltes) Drei-eck aus Blattern legt.
4. Schreiben Sie ein Programm, das vom Benut-zer die Anzahl der gewunschten Reihen er-fragt und dann den Rand eines entsprechen-den (gleichschenklig rechtwinkligen) Dreieckaus Blattern legt.
5. Schreiben Sie ein Programm, das vom Benut-zer die Anzahl der gewunschten Reihen erfragtund dann den Rand eines entsprechenden Qua-drats aus Blattern legt.
7 Vordefinierte Methoden in RUBYKARA
In der Umgebung von RUBYKARA stehen unterschiedliche Methoden zur Verfugung. Mankann sich eine Kurzbeschreibung der Methoden mit der Hilfe-Schaltflache des Welt-Fenstersanzeigen lassen. Die Methoden sind in verschiedene Gruppen eingeteilt.
Zunachst sind einige der Methoden dazu da, KARA zu Aktionen zu veranlassen:
move Ein Feld vorwartsturnLeft Vierteldrehung nach linksturnRight Vierteldrehung nach rechtsputLeaf Blatt ablegenremoveLeaf Blatt aufnehmen
Die Sensoren werden uber Methoden abgefragt, die als Ergebnis true oder false zuruckgeben.
treeFront Baum vorn?treeLeft Baum links?treeRight Baum rechts?onLeaf auf Blatt?mushroomFront vor Pilz?
Schließlich gibt es noch Methoden, KARA direkt auf einem bestimmten Feld zu positionierenund eine Methode, Karas Position abzufragen.
17
setPosition (x,y) setzt KARA auf das Feld mit den Koordinaten (x; y)setDirection(d) setzt KARAS Richtung: 0: Nord, 1: West, 2: Sud, 3: OstgetPosition.getX liefert KARAS x-KoordinategetPosition.getY liefert KARAS y-Koordinate
Alle diese Methoden mussen mit dem Prafix kara aufgerufen werden, also z. B. nicht move,sondern kara.move. Leider gibt es keine Methode zum Ermitteln von KARAS Richtung.
Es gibt auch Methoden zur direkten Veranderung von KARAS Welt. Sie mussen mit dem Prefixworld aufgerufen werden.
clearAll Alles entfernen (auch KARA ).setLeaf (x,y,legen?) legt (legen? = true ) oder entfernt (legen? = false ) ein Blatt bei (x;y)setTree (x,y,legen?) legt oder entfernt einen Baum bei (x;y)setMushroom (x,y,legen?) legt oder entfernt einen Pilz bei (x;y)setSize (xMax,yMax) Neue Große der Welt festlegengetSizeX horizontale Weltgroße zuruckgebengetSizeY vertikale Weltgroße zuruckgebenisEmpty(x,y) true , falls Feld (x;y) leer istisTree(x,y) true , falls ein Baum auf Feld (x;y) istisLeaf(x,y) true , falls ein Blatt auf Feld (x;y) istisMushroom(x,y) true , falls ein Pilz auf Feld (x;y) ist
Die nun folgenden Methoden sind in der Klasse tools definiert, mussen also mit dem Prefixtools aufgerufen werden. Diese Methoden sind vor allem fur Ein- und Ausgaben nutzlich. DerTyp string ist fur Zeichenketten (also Texte) bestimmt.
showMessage(text) gibt text in einem Dialogfenster ausstringInput(Titel) fordert die Eingabe eines Strings in einem Dialogfenster.
Titel liefert die Fensteruberschrift.Die Ruckgabe ist die Konstante null, fallsdie Eingabe abgebrochen wird.
intInput(Titel) Eingabe einer ganzen Zahl in einem Dialogfenstermit der Uberschrift Titel. Das Ergebnis istInteger.MIN_VALUE, wenn die Eingabe abgebrochenwird oder keine ganze Zahl eingegeben wird.
doubleInput(Titel) Eingabe einer Dezimalzahl in einem Dialogfenstermit der Uberschrift Titel. Das Ergebnis istDouble.MIN_VALUE, wenn die Eingabe abgebrochenwird oder keine Dezimalzahl eingeben wird.
random(Obergrenze) liefert eine ganze Zufallszahl aus demIntervall [0; Obergrenze]
sleep(ms) stoppt die Programmausfuhrung fur ms MillisekundencheckState uberpruft die Bedienungsleiste.
Unter Verwendung dieser Methoden kann man viele interessante kleine Probleme behandeln.
Aufgaben
1. Erzeugen Sie eine 20 × 20-Welt, umranden Sie sie mit Baumen und setzen Sie KARA aufdas Feld (10|10) mit Richtung Norden.
18
2. Schreiben Sie ein Programm, das die Anzahl der Baume einer Welt ermittelt und in einemMessage-Fenster ausgibt.
ANLEITUNG: Ermitteln Sie die Breite und Hohe der Welt und untersuchen Sie in einergeschachtelten Schleife die Felder der Welt darauf, ob auf ihnen ein Baum steht. KARA
wird dazu nicht benotigt!
3. Schreiben Sie ein Programm, das eine leere 15× 15-Welt erzeugt und in ihr per Zufall 25Baume verteilt.
HINWEIS: Verwenden sie die world- und tools-Funktionen. Erzeugen Sie zwei Zufalls-zahlen, um die Zeile und Spalte eines Feldes fur einen Baum auszuwahlen. Beachten Sie,dass kein Feld mehr als einmal ausgewahlt werden darf.
4. Lassen Sie KARA auf einem Feld beliebiger Große eine Zufallswanderung durchfuhren.Bei jedem Schritt geht KARA zufallsgesteuert ein Feld nach vorn oder nach links odernach rechts und legt ein Blatt ab, falls dort keines liegt. Zahlen Sie die Anzahl der Schritte,bis die Welt gefullt ist.
HINWEIS: Verwenden Sie random.
5. Andern Sie das vorige Programm so ab, dass KARA bei belegten Feldern auf seinem Wegdas Blatt aufnimmt. Lassen Sie KARA etwa so viele Schritte tun, wie in der vorigen Auf-gabe zum Fullen der Welt benotigt wurden und prufen Sie, wieviel der Welt dann mitBlattern bedeckt ist.
6. Man kann mit world.setLeaf(x,y,true) auf dem Feld (x|y) ein Blatt ablegen. Man kanndies verwenden, um Muster zu erzeugen. Schreiben Sie eine Klasse, die eine 20× 20-Welterzeugt, im oberen linken Eck ein zufalliges 4 × 4-Muster aus Kleeblattern erzeugt unddieses Muster dann auf die ganze Welt kopiert.
⇒7. Die angezeigten Ziffern sollen jeweils mit einer eigenen Methode erzeugt werden.
Dabei gibt es folgende Vorgaben:
• Jede Ziffer beansprucht ein Rechteck mit 6× 8 Feldern.
• In den seitlichen Randern des Rechtecks liegen keine Blatter.
• die Methode erhalt als Eingabe die Koordinaten des linken unteren Eckfelds desRechtecks.
Die Eins kann man beispielsweise wie folgt erzeugen:
19
1 def e ins ( x , y )2 2 . upto ( 4 ) { | i | @world . s e t L e a f ( x+i , y , t rue )}3 1 . upto ( 7 ) { | i | @world . s e t L e a f ( x +3 ,y−i , t rue )}4 1 . upto ( 2 ) { | i | @world . s e t L e a f ( x+i , y−4−i , t rue )}5 end
Analysieren Sie diese Methode und schreiben Sie Methoden fur die restlichen Ziffern.Schreiben Sie damit ein Programm, welches das oben gezeigte Bild erzeugt.
HINWEIS: Es empfiehlt sich, eine allgemeine Methode
public void schreibe(int ziffer,int x,int y)
zu schreiben, die je nach Ziffer die passende Schreibmethode wahlt. Dazu sollte man sichansehen (Internet), wie man Mehrfachfallunterscheidungen in RUBY mit case realisiert.
8. Schreiben Sie unter Verwendung der vorigen Aufgabe ein Programm, das eine naturlicheZahl vom Benutzer erfragt und diese Zahl dann in eine passende Welt schreibt.
HINWEIS: Den Divisionsrest von a:b erhalt man durch a % b. Im Bereich der ganzen Zah-len liefert RUBY immer den ganzzahligen Quotienten ohne Rest, wenn man a/b berech-net. anders ausgedruckt: Gilt a = q · b + r mit r < b, so ist a/b = q und a % b = r.
9. Von Manfred Eigen (http://de.wikipedia.org/wiki/Manfred_Eigen) stammt die folgen-de Simulation zum Thema Evolution.Man nehme ein 8 × 8-Feld und belege es in je-dem der vier Teilquadrate mit einem Symbol,wie rechts gezeigt (das vierte ”Symbol“ ist hierganz einfach ein leeres Feld). Nun wird fol-gendes Verfahren wiederholt, bis nur noch eineSymbolsorte auf dem Feld ist: Man wahlt perZufall zwei verschiedene Felder des Quadrats.Das Symbol auf dem ersten Feld wird entferntund durch ein Symbol von der Art des auf demzweiten Feld befindlichen ersetzt. Startbelegung
Schreiben Sie ein Programm, das diese Simulation durchfuhrt.
8 Erweiterungen
Eine Reihe von Problemen waren einfacher losbar, wenn KARA mehr Sensoren hatte. Man kanneigene Sensoren als Methoden leicht zusatzlich definieren.
Beispiel: Es soll ein Sensor definiert werden, der einen Pilz links von KARA entdeckt.
Dazu muss sich KARA nach links drehen, sich merken, ob jetzt vor ihm ein Pilz steht und sichdann zuruck nach rechts drehen.
1 def pi lzL inks2 @kara . t u r n L e f t3 p i l z =@kara . mushroomFront4 @kara . turnRight
20
5 return p i l z6 end
Nach diesem Verfahren kann man naturlich auch einen Sensor fur rechts von KARA stehendePilze definieren. Allerdings hat das Verfahren den Nachteil, dass KARA bewegt werden muss,was die Programmausfuhrung verlangsamt. Will man entsprechend Sensoren definieren, dieerkennen, ob KARA links von, rechts von oder vor einem Blatt steht, so wird der Aufwandnoch hoher, weil der vorhandene Sensor Blatter nur erkennt, wenn KARA auf ihnen steht. Umzu erkennen, ob KARA vor einem Blatt steht, muss KARA daher einen Schritt vorwarts machen.Das geht aber nicht immer. KARA konnte vor einem Baum stehen, dann kann er keinen Schrittvorwarts machen. Steht er vor einem Pilz, so kann er vielleicht einen Schritt vorwarts machen,verschiebt aber dabei den Pilz.
Wenn man die Methoden der Klasse world verwendet, kann man alternativ etwa folgendenSensor erzeugen:
1 def l ea fSouth2 y=@kara . g e t P o s i t i o n . getY3 x=@kara . g e t P o s i t i o n . getX4 ymax= @world . getSizeY−15 i f y==ymax6 return @world . i s L e a f ( x , 0 )7 e lse8 return @world . i s L e a f ( x , y + 1 ) ;9 end
10 end
Hier wird zunachst KARAS Position abgefragt. Dabei muss berucksichtigt werden, dass dieWelt in form einer Torus vorliegt. Wenn KARA auf der untersten Zeile steht, so ist die obersteZeile ”sudlich“ von KARA . Dem wird mit der Fallunterscheidung Rechnung getragen.
Entsprechend kann man auch Methoden schreiben, die KARA in eine bestimmte Himmelsrich-tung drehen. Naturlich kann das auch direkt mit kara.setDirection bewerkstelligt werden,aber eine passende Neudefinition ist einpragsamer:
1 def turnEast2 @kara . s e t D i r e c t i o n ( 3 )3 end
Wenn man eine Reihe solcher Definitionen haufiger verwenden will, kann man sie in einer eige-nen von JavaKaraProgram abgeleiteten Klasse definieren. Die ganzen Definitionen der Senso-ren und die Drehungen sind beispielsweise in der Datei Kepi.rb zusammengestellt. Die Dateienthalt nur Definitionen und kein Programm. Speichert man diese Datei im Verzeichnis derDatei rubykara.jar, so kann man danach mit dem Befehl require ’Kepi.rb’ zu Beginn einerProgrammdatei diese Definitionen einschließen und verwenden.
Das folgende Programm verwendet diese Methode, um eine vereinfachte Fassung von Pacmanzu erzeugen:
1 requi re ’ Kepi . rb ’2
3 @kara . removeLeaf i f @kara . onLeaf4 while not @kara . t r e e F r o n t
21
5 i f l e a f E a s t6 turnEast7 e l s i f leafWest8 turnWest9 e l s i f l ea fSouth
10 turnSouth11 e l s i f leafNorth12 turnNorth13 e lse r a i s e ”Kein B l a t t weit und b r e i t :−( ”14 end15 @kara . move16 @kara . removeLeaf17 end
Aufgaben
1. Schreiben Sie nach den Beispielen in diesem Abschnitt die vollstandige Datei Kepi.rbund testen Sie das pacman-Programm.
9 Arrays
Wir wollen den verwendeten Zufallszahlengenerator tools.random(n) benutzen, um einenWurfel zu simulieren. Dazu sollen hundert Zufallsszahlen im Bereich von 1 bis 6 erzeugt wer-den. Wir wollen die Anzahlen festhalten, mit denen jede der Zahlen erzeugt wird.
Die Zufallszahlen werden mit folgender Methode erzeugt (random(5) erzeugt Zahlen von 0 bis5):
1 def wurfel2 return (1+ @tools . random ( 5 ) ) ;3 }
Zum Mitzahlen der einzelnen Ergebnisse konnte man jetzt sechs Variablen definieren und diesemit einer Fallunterscheidung bei jedem Ergebnis um eins erhohen. Dies ware außerst umstand-lich. Da solche und ahnliche Probleme haufig auftauchen, sehen die meisten Programmierspra-chen auch Datenstrukturen vor, die solche Aufgaben vereinfachen.
Will man mehrere Daten gleichen Typs gruppieren, verwendet man einen Array (deutsch:Feld). In einem Array werden eine feste Anzahl von Daten gleichen Typs gespeichert. Auf dieeinzelnen Daten kann man uber einen Index zugreifen. In RUBY werden Arrays beispielsweisewie folgt vereinbart:
zahlen=[1,2,3,4,5,6];
Diese Anweisung definiert eine Array-Variable zahlen mit 6 Eintrage vom Typ int, die mitden in den eckigen Klammern stehenden Zahlen initialisiert werden. Auf das dritte Elementdes Arrays wird mit dem Ausdruck zahlen[2] zugegriffen (die Zahlung der Array-Elementebeginnt mit 0).
Alternativ kann man ein Array auch ohne Initialisierung definieren und die Zuweisung vonWerten spater vornehmen. Mit der folgenden Methode wird die Anzahl der Elemente des Ar-rays festgelegt. Dabei wird automatisch jedes Element mit einem Standardwert nil initialisiert.
22
werte=Array.new(100);
erzeugt einen Array mit 100 Elementen , die alle mit nil initialisiert werden. Man kann auchBlocke zur Initialisierung verwenden:
zahlen=Array.new(6) {|i| i+1}
erzeugt ebenfalls den Array [1,2,3,4,5,6]. Der Variablen i des Blocks wird dabei fur jedesneue Arrayelement dessen Index ubergeben. Das Ergebnis der Berechnung des Blocks wirddann diesem Element zugewiesen. Mit
zahlen=Array.new(10){|i| [i,i*i]}
erhalt man einen Array von 10 zweielementigen Arrays die jeweil eine der Zahlen von 0 bis 9und ihr Quadrat enthalten.
Das Programm fur die 100 Wurfe des Wurfels konnte so aussehen:
1 ergebnis=Array . new ( 6 , 0 )2 1 0 0 . t imes { ergebnis [ @tools . random ( 5 ) ] +=1}3 @tools . showMessage ( ergebnis . i n s p e c t )
Der Array ergebnis wird mit 6 Elementen definiert, die alle den Wert 0 erhalten. So kann manfur jede Zahl i des Wurfels ganz einfach das ite Element von ergebnis als Zahler verwenden.Da die Array-Indizes von 0 bis 5 gehen, verwendet man einen ”Wurfel“ mit den Augenzahlenvon 0 bis 5. Man kann naturlich leicht auch großere Anzahlen von Wurfen simulieren. Mitinspect wird der Array fur die Ausgabe in einen String umgewandelt.
Aufgaben
1. Schreiben Sie ein Programm, das vom Benutzer den Funktionsterm einer Funktion (Funk-tionsvariable: x) anfordert und fur diesen Funktionsterm eine Wertetabelle fur die ganz-zahligen Werte von x von -5 bis 5 ausgibt.
HINWEIS: @tools.stringInput kann zur Eingabe des Terms verwendet werden. Die Me-thode eval kann einen String auswerten, wenn dieser einen gultigen RUBY -Ausdruckdarstellt.
BEISPIEL x=3; eval("x**2+2*x+1") liefert als Ergebnis 16.
2. Schreiben Sie ein Programm, welches die Baume, Pilze und Blatter einer Welt mit einemArray zahlt und das Ergebnis anzeigt.
3. Simulieren Sie ein Galtonbrett mit Kara als ”Kugel“ und ”Baumen“ als Stifte.
(Informationen dazu unter http://de.wikipedia.org/wiki/Galtonbrett)
23