Foto: Uwe Pirr
Informatik
|
|
Nachdem wir im ersten Teil dieses Kurses unsere ersten Erfahrungen mir
HyperTalk gemacht haben, ist es nun an der Zeit, diese ein wenig zu
systematisieren. Im Gegensatz z.B.. zu C oder PASCAL ist HyperTalk eine
interpretierende Programmiersprache, wie z.B. auch BASIC. Neben der dadurch in
Kauf zu nehmenden relativen Langsamkeit von HyperCard ist damit auch eine
gewisse Freiheit verbunden, die im strikten Gegensatz zu der Strenge von
strukturierten Sprachen wie PASCAL oder MODULA-2 steht. Zwar erleichtert
dies die Entwicklung von kleinen Quick & Dirty Programmen,
erhöht jedoch die Gefahr, daß sich der Programmierer bei
größeren Projekten in seinem unübersichtlich gewordenen
Programmcode verliert. Auch dies ist eine Art von Lost in Cyberspace! Um
dies zu vermeiden, sollten von Anfang an gewisse Grundregeln eingehalten
werden. Glücklicherweise unterstützt HyperTalk vielfach die
Möglichkeiten der strukturierten Programmierung, ohne sie jedoch zu
erzwingen. Ich werde daher in diesem Kurs immer wieder Konventionen
vorschlagen, die das Leben des HyperTalk-Programmierers erleichtern helfen.
Erst einmal aber werden wir die grundlegenden Sprachelemente von HyperTalk
kennenlernen.
HyperTalk kennt im Prinzip nur einen einzigen Datentyp, den Datentyp
Text. Alles wird erst einmal als Text behandelt - nur wenn aus dem
Kontext einwandfrei etwas anderes zu erschließen ist, wird der Text in
Zahlen konvertiert. Wenn also im Script steht
put 3*a into ergebnis
erkennt HyperTalk aus dem Kontext, daß a eine
numerische Variable sein und das Ergebnis von 3*a in die Variable
ergebnis geschrieben werden soll. Dies ist erst einmal sehr einfach,
kann jedoch zur Verwirrung und auch zum verzögerten Programmablauf
führen, da HyperTalk erst nachprüfen muß, wie z.B. folgendes
Script-Fragment gemeint ist:
put 3*a into cd fld ergebnis
Hier kann ergebnis einmal der Name des Feldes sein oder aber
eine String-Variable (eine Textvariable) in der der Name des gewünschten
Kartenfeldes steht. HyperTalk muß also erst einmal nachprüfen, ob
irgendwo im Script vorher folgender Text stand:
put "Summe" into ergebnis
Dies würde nämlich bedeuten, daß das Ergebnis im
Kartenfeld "Summe" abgespeichert werden soll. Um hier HyperTalk die
Arbeit zu erleichtern und die Ausführung des Scriptes zu beschleunigen,
sollten Sie, falls ergebnis tatsächlich der Name des
gewünschten Feldes ist, dies in Hochkommata einschließen:
put 3*a into cd fld "ergebnis"
Dann weiß HyperTalk, daß ein Name und keine Variable
gemeint ist und erspart sich das zeitraubende Nachsehen. Bei zusammengesetzten
Namen, wie z.B. "Ergebnis alt" ist dies sowieso erforderlich. Daher sollten Sie
sich diesen Hochkommata-Einschluß von Anfang an angewöhnen. Als
angenehmen Nebeneffekt erleichtert es auch das Lesen von
HyperTalk-Programmen.
Zusammengesetzte und strukturierte Datentypen, wie wir sie aus den oben
genannten höheren Programmiersprachen kennen, sind in HyperTalk unbekannt,
können jedoch, wie ich in einem späteren Beitrag dieses Kurses zeigen
werde, über Felder leicht simuliert werden.
Variable heißen in HyperTalk Container und müssen nicht
explizit deklariert werden. So bald ein Name zum erstenmal in einem Script
auftaucht, nimmt HyperTalk an, daß es sich um einen Container handelt.
Da, wie oben erwähnt, HyperTalk nur den Datentyp Text kennt, kann ein
Container im Laufe seines Lebens alle möglichen Werte enthalten. So kann
im Script stehen
put 3.14159/2 into piHalbe
put line i of cd fld "Magermilch" into piHalbe
HyperTalk kennt lokale und globale Container. Normalerweise sind alle
Container lokal, daß heißt nur in Bereich ihres Handles sichtbar.
Wenn also in einem Script steht:
on erstes
put 25 into ergebnis
...
end erstes
on zweites
put "Magermilch" into ergebnis
...
end zweites
dann existieren zwei Variable ergebnis mit unterschiedlichem
Inhalt, die beide nur innerhalb ihres Handles erstes oder
zweites gültig sind.
Globale Variablen müssen dagegen explizit in jedem Handle als global
deklariert werden. Im Beispielprogramm "Der blinde Uhrmacher" (siehe unten) ist
der Container summe als global deklariert.
Im Gegensatz zu Feldern, deren Größe auf 32 kByte beschränkt
ist, ist die Größe von Containern nur durch den vorhandenen
Hauptspeicher begrenzt. Ich habe schon testweise den Inhalt eines ganzen Buches
in einen einzigen Container eingelesen und diesen dann im Hauptspeicher
indiziert (was dann sehr schnell geht). Allerdings hatte der Rechner einen
Hauptspeicher von ca. 150 MByte und dies dürften wohl die wenigsten
Leserinnen und Leser dieses Kurses zur Verfügung haben. Und auch, wenn die
Operationen im Hauptspeicher schneller ausfallen, ziehe ich es in der Regel
vor, größere Datenmengen über Felder zu realisieren. Einmal
kann ich im Fehlerfalle immer noch in den Feldern nachschauen, was mein Script
da eigentlich hineingeschrieben hat und zum anderen können auf Feldinhalte
ohne die umständliche Global-Deklarationen alle Handle zugreifen.
HyperTalk enthält einige eingebaute Konstanten, wie z.B. empty für
die leere Zeichenkette "", pi für 3.1459265358979323864 oder space
für das Leerzeichen. Eine vollständige Aufzählung entnehmen Sie
bitte Ihrem Manual. Eine explizite Konstantendeklaration hingegen kennt
HyperCard nicht. Entweder werden Sie durch Zuweisung und gegebenenfalls. einer
Global-Deklaration, z.B.
global epsilon
put 0.00001 into epsilon
realisiert oder besser, wie ich weiter unten noch zeigen werden,
über Funktionen.
Die Verzweigung if <Bedingung> then <Anweisung> else
<Anweisung> haben wir im ersten Teil unseres HyperTalk-Kurses schon
kennengelernt. Alle durch andere Programmiersprachen bekannten
Schleifenkonstrukte werden in HyperTalk durch das Schlüsselwort
repeat eingeleitet. Es gibt im Einzelnen:
repeat forever
<Anweisungen>
end repeat
Dies ist die bekannte und berüchtigte Endlosschleife. Sie
kann nur mit exit repeat, pass oder return
wieder verlassen werden.
repeat for i times
<Anweisungen>
end repeat
Diese Schleife wird i mal durchlaufen, wobei der Programmierer
sicherstellen muß, daß i einen ganzzahligen Wert (Integer-Wert)
enthält. Ansonsten erfolgt eine Fehlermeldung.
repeat with i = <Startwert> [down] to <Endwert>
<Anweisungen>
end repeat
Diese Schleife entspricht der aus anderen Programmiersprachen
bekannten Zählschleife. Bei jedem Durchlauf erhöht sich der
Wert der Variable i um 1. (Bei down to wird der Wert der
Variable um 1 vermindert). Die Schleife wird verlassen, wenn
<Endwert> erreicht ist.
repeat until <Bedingung>
<Anweisungen>
end repeat
repeat while <Bedingung>
<Anweisungen>
end repeat
Die obere Schleife wird solange durchlaufen, bis (until) die
Bedingung wahr (TRUE) ist, die untere Schleife solange wie, die
Bedingung wahr ist. Der Unterschied leuchtet nicht nur
Programmieranfängern nicht so ohne weiteres ein: Beide Schleifen sind
beinahe gleich, nur wird die obere Schleife immer mindestens einmal
durchlaufen, während die untere gar nicht durchlaufen wird, wenn die
Bedingung schon beim ersten Durchlauf TRUE ist (abweisende
Schleife). Dieser Unterschied kann unter Umständen wichtig sein,
meistens ist er jedoch ohne Bedeutung. Auch in den Beispielprogrammen habe ich
einmal die "until"- und einmal die "while"-Schleife nur aus didaktischen
Gründen gewählt.
Wie wir gesehen haben, werden die einzelnen Script-Teile eines
HyperTalk-Programmes durch Handles der Form
on <handle>
<Anweisungen>
end <handle>
gegliedert. Dabei kann ein Handle sich auch selber aufrufen. Dieses
Prinzip der Rekursion werden wird in einem späteren Beitrag dieses Kurses
behandeln. Ein Handle wird aktiv, sobald die entsprechende message,
sei es eine Systembotschaft, wie mouseUp, sei es eine
benutzerdefinierte Botschaft, bei ihm eintrifft. Ebenso wie Prozeduren,
können auch einem Handle Parameter übergeben werden, z.B.
on initialisiere startwert
put startwert into cd fld "Start"
end initialisiere
Dieses Handle kann dann zum Beispiel mit initialisiere(27)
aufgerufen werden. Jedoch kann ein Handle keine Parameter zurückgeben.
Würde also startwert in obigem Handle verändert, hätte
dies keinen Einfluß auf das aufrufende Script - es sei denn,
startwert wäre in beiden Scripten als global vereinbart gewesen.
Dann hätte es aber nicht als Parameter übergeben werden
müssen.
Funktionen werden statt mit on mit dem Schlüsselwort
function eingeleitet. Der Rückgabewert wird mit return
zurückgegeben. Hätte HyperTalk nicht schon einen eigenen, so
könnten wir z.B. folgenden kleinen Zufallszahlengenerator programmieren
(nach Reiser/Wirth: Programmieren in Oberon, Bonn (Addison-Wesley)
1994):
on initSeed seed
global z
put seed into z
end initSeed
function uniform
global z
put 16807 into a
put 2147483647 into m
put m div a into q
put m mod a into r
if gamma > 0 then
put gamma into z
else
put gamma + m into z
end if
put z*(1/m) into z
return z
end uniform
Das Handle initSeed initialisiert den Zufallszahlengenerator.
Dieser Initialwert ist global deklariert und damit auch für die Funktion
uniform sichtbar. Damit der Generator funktioniert darf und muß
initSeed nur einmal aufgerufen werden. uniform ist als
Funktion realisiert und der Aufruf von
put uniform() into zufall
liefert, wenn man Wirth und Reiser glauben darf, gleichverteilte
Zufallszahlen im Intervall ]0..1[. Ich möchte in einem späteren
Beitrag einmal diesen und andere Zufallszahlengeneratoren mit dem in HyperTalk
eingebauten vergleichen.
Wie wir an obigem Beispiel sehen, liefert HyperTalk auch die
Ganzzahl-Operatoren mod und div: Ihre Funktion wird deutlich,
wenn wir uns die normale Division ansehen (5 : 2 = 2,1). Als Ganzzahloperator
liefert mod den Rest (nach dem Komma) einer Division zweier ganzer
Zahlen (also: 5 mod 2 = 1), div den ganzzahligen Anteil (vor dem
Komma) einer Division zweier ganzer Zahlen (also: 5 div 2 = 2).
Abb. 1: Das Evolutionsspiel
Mit diesem Wissen sind wir nun in der Lage, unser erstes komplexeres
HyperTalk-Programm zu schreiben. Es ist ein Spiel, mit dem die Statistik der
Evolution untersucht wird und stammt aus dem Buch von Manfred Eigen und Ruthild
Winkler: Das Spiel. Naturgesetze steuern den Zufall,
München/Zürich (Piper-Verlag) 1975. Es ist ein sehr empfehlenswertes
Buch mit vielen weiteren naturwissenschaftlich interessanten Simulationsideen.
Bei Eigen/Winkler ist das Evolutionsspiel als (von Menschen ausgeführtes)
Würfelspiel mit bunten Kugeln vorgeschlagen, wir hingegen überlassen
das Würfeln lieber HyperTalk und ersetzen die Kugeln durch Zahlen. (Wenn
wir nach der nächsten Folge die grafischen Möglichkeiten von
HyperCard erkundet haben, bleibt es dem Leser überlassen, das Spiel in
einer grafischen Variante zu programmieren.) Bei diesem Spiel siegt immer eine
Farbe (eine Zahl) und es ist ein Modell für das darwinsche Survival of
the fittest..
Die Spielregeln: Auf einem 6 x 6 großem Feld werden anfangs
gleichverteilt die Ziffern von eins bis sechs ausgelegt. Wir erledigen dies mit
Hilfe des in HyperCard eingebauten Zufallszahlengenerators:
repeat with i = 1 to 6
repeat with j = 1 to 6
put random(6) into neu
put neu into item i of line j of cd fld~
"Spielfeld"
add 1 to cd fld (neu + 3)
end repeat
end repeat
Zuvor haben wir das linke große Feld "Spielfeld" angelegt und
die Schriftgröße so gewählt, daß das Feld ungefähr
ausgefüllt wird. Und in diesem Feld sehen wir eine weitere Besonderheit
von HyperTalk: Auch Matrizen (für PASCAL-Programmierer: zweidimensionale
Arrays) werden in HyperTalk über Felder realisiert. Dabei sind line die
Zeilen und item die Spalten der Matrix. Wie wir an der Zeichnung sehen
können, werden die einzelnen Elemente durch Kommata getrennt in dem Feld
abgespeichert.
Während des Spiels erwürfeln wir mit zwei Würfeln die Zeile und
Spalte der Matrix. Danach erwürfeln wir genauso ein zweites Feld. Dort
wird dann die darin vorhandene Ziffer durch die Ziffer des ersten
erwürfelten Feldes ersetzt. Jede erwürfelte Ziffer verdoppelt sich
also auf Kosten einer anderen auf dem Spielfeld. Sie können das Spiel
spielen, so oft sie wollen: Nach einer gewissen Zeit wird immer eine Ziffer,
die das gesamte Spielfeld besetzt hält, als Sieger hervorgehen.
Jetzt weiter zur Realisierung: Nach dem Spielfeld habe ich das Feld "Anzahl"
unten rechts neben "Spielzüge" angelegt und danach das Titelfeld, in dem
nur die Überschrift steht und das auch sonst keine weiteren Funktionen
hat. Ich füge grundsätzlich Texte auf den Karten in Feldern ein, sie
lassen sich einmal leichter korrigieren und zum anderen kann man danach suchen
lassen. Gegenüber dem auch möglichen Einfügen von Texten im
Grafikmodus hat dies den Nachteil, daß auf dem Rechner, auf dem der Stack
läuft auch die Schrift vorhanden sein muß. Daher benutze ich
grundsätzlich nur die Schriften Courier, Geneva und New York. Diese sind
mit Sicherheit auf jedem Macintosh vorhanden.
Durch die oben angegebene Reihenfolge haben die danach von oben nach unten
angelegten Felder rechts neben "Eins" bis "Sechs" die Feldnummern 4, 5, 6, 7, 8
und 9 erhalten. So wird folgendes Codefragment (aus dem Handle
initialisiere) verständlich:
repeat with i = 4 to 9
put 0 into cd fld i
end repeat
Feldern lassen sich nicht nur mit ihrem Namen, sondern auch mit ihrer
Nummer ansprechen. So ist es möglich, diese Felder innerhalb einer
Schleife mit "0" zu füllen. Dies ist notwendig, weil die add und
sub Kommandos von HyperTalk mit einer Fehlermeldung reagieren, wenn
der angesprochene Container oder das angesprochene Feld keinen numerischen Wert
enthalten. Und leere Felder haben in HyperTalk den Wert empty, sind
also nicht numerisch, wohingegen bei Null HyperTalk mit uns übereinstimmt,
daß dies ein numerischer Wert ist.
Im Handle playGame erwarten uns keine Neuigkeiten mehr, außer
vielleicht, daß uns folgende Zeile
set the textStyle of item x2 of line y2~
of cd fld "Spielfeld" to outline
zeigt, daß wir die Textattribute auch von HyperTalk aus
beeinflussen können. Wie ich im letzten Beitrag schon geschrieben hatte:
Alles, was wir in HyperCard mit Maus und Tastatur erledigen können,
können wir auch von HyperTalk aus programmieren. (Eine Ausnahme bilden
lediglich einige Color-Tools von HyperCard 2.3. Doch hierzu mehr in einem
späteren Beitrag.) Wichtig ist auch noch das Häkchen am Ende der
ersten Zeile, das mit der Tastenkombination [Wahl][L] erzeugt werden kann.
Normalerweise enden HyperTalk Befehle am Ende der Zeile, mit diesem
Häkchen wird HyperTalk signalisiert, daß sich ein Befehl in der
nächsten Zeile fortsetzt.
Ansonsten ist nur noch zu bemerken, daß sich das ganze HyperTalk-Programm
für dieses Spiel hinter dem Button "Start" verbirgt und in
Listing 1
abgedruckt ist.
Abb. 2: Shakespeare und der blinde Uhrmacher
Noch etwas komplexer ist das zweite Beispielprogramm "Der blinde Uhrmacher",
das sich ebenfalls mit der Evolution beschäftigt. Wir alle kennen das
Beispiel des Schimpansen an der Schreibmaschine, der, wenn er nur unendlich
lange genug in die Tasten hackt, irgendwann einmal auch einen Satz aus
Shakespeares Hamlet (vielleicht "To be or not to be") hervorbringt. Statistisch
gesehen dauert dies jedoch beinahe unendlich lange. Dawkins hat sich in seinem
Buch Der blinde Uhrmacher, München (dtv) 1990) gefragt, was denn
passiert, wenn man zufällige Mutationen immer wieder auf das Ergebnis
anwendet, das dem Ziel am nächsten kommt. Im Buch ist es der Satz
"Methinks it is like a weasel" (Mich dünkt, sie sieht aus wie ein Wiesel),
ebenfalls aus Hamlet. Dieses Prinzip der kumulativen Selektion führt schon
recht schnell zu einem Ergebnis. Dawkins gibt 50 - 60 Generationen an, macht
jedoch weder Angaben über die Mutationshäufigkeit noch über die
Anzahl der "Nachkommen" jedes Zwischenergebnisses, auf dem die Mutationen
angewandt werden. Unser Beispielstack arbeitet mit 20 Nachkommen, auf denen je
eine zufällige Veränderung vorgenommen wird. Ich habe diesen Stack
lange laufen lassen. Im Schnitt wird der Zielsatz nach ca. 150 Generationen
erreicht. Der beste Wert lag bei knapp über 100, der schlechteste bisher
bei knapp unter 200 Generationen. Und Vorsicht: Selbst auf meinem Power PC lief
der Stack jedes Mal ca. eine halbe Stunde!
Wir beginnen mit diesem Stack, indem wir als erstes ein Kartenfeld "children"
anlegen. Dieses Feld soll unsichtbar sein, nur zum Zweck der Fehlersuche
mußte ich es bei der Entwicklung sichtbar machen. Mit [Apfel][M] holen
wir uns daher wieder die Messagebox aus dem ersten Teil dieses Kurses auf den
Monitor. Mit Hilfe der Messagebox können HyperTalk-Kommandos interaktiv
eingegeben werden. Wir tippen daher
hide cd fld "children"
in die Box und tippen [ENTER]. Und siehe da, das Feld "children" ist
verschwunden. Mit
show cd fld "children"
können wir es jederzeit wieder sichtbar machen und seinen Inhalt
überprüfen. Ich hätte genau so gut das, was in dieses Feld
geschrieben wird, in einem Container abspeichern können, aber ich
mußte tatsächlich mal während der Programmentwicklung den
Inhalt kontrollieren und einen Container hätte ich dazu erst wieder
umständlich in ein Feld schreiben müssen.
Natürlich soll im fertigen Programm das Feld nicht mehr zu sehen sein. Wir
wählen daher "Card Info..." aus dem Menü "Objects", drücken in
der Dialogbox den Knopf "Script" und geben folgendes HyperTalk-Script ein:
on openCard
hide cd fld "children"
pass openCard
end openCard
openCard ist ein ähnliches Systemhandle wie mouseUp. Er
wird von HyperCard immer dann abgeschickt, wenn die entsprechende Karte
aufgerufen wird. Wir fangen es in unserem Script ab und setzen den Befehl
hide cd fld "children" dort ein. Es ist guter Brauch, solche
abgefangenen Systemhandles weiterzugeben (mit pass <handle>),
damit es auch an anderer Stelle, z.B. in einem Background-Script,
wiederverwendet werden kann.
Wir ersehen daraus, daß nicht nur hinter Buttons in HyperCard Scripte
versteckt sein können. Hinter jedem Objekt kann sich ein Script verbergen,
hinter Feldern, Hintergründen, Karten, Stapeln, ja sogar im Home-Stack.
(Dort verbergen sich tatsächlich noch einige System-Scripts. Es ist jedoch
schlechter Stil, eigene Scripte im Home-Stack unterzubringen, da die Stacks
dann auf anderen Computern nicht mehr laufen.)
Wir legen nun auf unserem Stack noch weitere Felder an: Das linke große
heißt "intermediate", das über dem Startknopf "goal" und das
darüber "parent". Diese Felder erhalten die Schrift Courier, da nur diese
streng nonproportional ist, d.h. die Buchstaben immer genau
untereinanderstehen. So können wir die Annäherung an den Zielsatz
optisch leicher verfolgen. Das Feld neben dem Text "Anzahl Generationen"
heißt "generation" und das darüber neben "Anzahl
Übereinstimmung" habe ich "summe" genannt. Auch in diesem Stack sind alle
Texte auf der Karte ebenfalls in Feldern, dies hat hier jedoch nur einen
kosmetischen Effekt und ist für die Programmausführung
bedeutungslos.
Bis auf das oben erwähnte Card-Script verbirgt sich auch hier das gesamte
Programm hinter dem einzigen Button "Start". Die Struktur des Scripts ist
ähnlich wie bei dem Evolutionsspiel, auf das Handle mouseUp folgt
das Handle initialisiere und dann das Handle evolution mit
dem eigentlichen Algorithmus. Dann folgt noch die Funktion makeLetter,
die zufällig einen (Groß-)Buchstaben auswählt. Hier wird nur
ein bißchen gebastelt, da unser im Programm benutztes Alphabet die 26
Großbuchstaben und das Leerzeichen enthält. Die Großbuchstaben
haben die ASCII-Nummern 65 - 90, das Leerzeichen den ASCII-Wert 32.
random(27) liefert uns einen zufälligen Wert zwischen 1 und 27.
Wir addieren 63 auf. Die in HyperTalk eingebaute Funktion numToChar
liefert uns dann das Gewünschte. Nur wenn der Zufallszahelngenerator 1
liefert, das Ergebnis also 32 ist, müssen wir durch 2 teilen, um den
ASCII-Wert für das Leerzeichen zu erhalten.
Die beiden letzten Funktionen dagegen sind ein kleiner Trick. Um Konstanten
nicht immer wieder neu zu definieren oder versehentlich zu überschreiben
sind sie ebenfalls als Funktionen realisiert:
function anzNachkommen
return 20
end anzNachkommen
Jedesmal, wenn im Programm anzNachkommen() aufgerufen wird,
ist damit diese Konstante gemeint. Mit dem kleinen Mehraufwand, die
öffnenden und schließenden Klammern zu tippen (und natürlich
die Konstantendeklaration als Funktion zu realisieren) erhalten wir die
Sicherheit, die die Konstantendeklaration der "höheren"
Programmiersprachen bieten.
Ansonsten bietet das Programm, das komplett in
Listing 2 abgedruckt ist, nur
noch wenige Neuheiten: Wenn wir lange auf eine Antwort eines Programmes warten,
sollten wir den Benutzer davon informieren, daß der Rechner nicht
abgestürzt ist. Eine Möglichkeit ist der Befehl
set cursor to busy
Jedesmal, wenn er aufgerufen wird, dreht sich der busy-Cursor (dieser
kleine, schwarzweiße Ball) um einen Viertelkreis. Wir merken somit,
daß noch etwas passiert. Es sollte nicht vergessen werden,
anschließend den Cursor wieder zu hand zurückzusetzen.
Dann ist noch das Feld intermediate als Scrollfeld realisiert. Ohne
weiteren Befehl schreibt HyperTalk zwar auch in den unsichtbaren Teil des
Feldes, der Benutzer sieht aber während der Programmausführung nicht,
was da hineingeschrieben wird. Daher habe ich mit dem Kommando
set the scroll of cd fld "intermediate" to 9999
dafür gesorgt, daß nach jedem Einschreiben das Feld ganz
nach unten gerollt wird. (Der Wert 9999 ist einfach geschätzt worden, weil
er sehr groß ist und der Scroll in Pixeln berechnet wird. Bei
größeren Scrollfeldern kann er daher noch zu klein sein und ist
entweder durch einen berechneten Wert oder durch noch eine größere
Zahl zu ersetzen.)
Außerdem sind unser verstecktes Feld children und die anderen
Felder diesmal nicht als Matrix realisiert. Auf die einzelnen Buchstaben
greifen wir daher mit der Sequenz char j of line i zu. Die Buchstaben
sind so auch nicht durch Kommata getrennt. Neben den nun bekannten
item und char können wir auch mit chunk und
word in HyperCard auf einzelne Elemente eines Textfeldes zugreifen.
Dies werden wir in einem späteren Kursteil, wenn wir Hypertext-Elemente
realisieren werden, noch benötigen.
Als letzte Neuheit habe ich diesmal für die umfassende Schleife die
repeat while-Konstruktion gewählt. Aber wie schon oben gesagt,
geschah dies aus didaktischen Gründen und hat in diesem Beispiel keinen
praktischen Wert.
Der im "Blinden Uhrmacher" verwendete Algorithmus ist eine nur auf Mutation
beruhende Evolutionsstrategie ohne crossing over. Mit crossing
over wird der Vorgang bezeichnet, zwei für die Weiterentwicklung
ausgewählte "Nachkommen". zu "kreuzen", um so vielleicht einen
geeigneteren Nachkommen zu finden. Solche Algorithmen heißen genetische
Algorithmen. (Theoretische Informatiker mögen mir die arg verkürzte
Darstellung verzeihen!) Wir haben bisher alles gelernt, um aus dem "Blinden
Uhrmacher" einen genetischen Algorithmus zu machen. Denn während sonst das
zu lösende Problem mühsam in eine Zeichenkette (meist in binärer
Darstellung) codiert werden muß, um ein Auseinanderschneiden und
Zusammenfügen zu ermöglichen, liegt unser Problem schon in der Form
einer Zeichenkette vor. Statt eines Nachfolgers wählen wir zwei aus (es
müssen nicht unbedingt die "besten" sein). Beide Zeichenketten werden an
einer zufälligen Stelle auseinandergeschnitten und mit dem jeweils anderen
Teil wieder zusammengefügt. Wir müssen daher nur noch wissen,
daß der HyperTalk-Befehl zum Zusammenfügen zweier Teilstrings
& oder && ist. & fügt zwei
Zeichenketten unmittelbar zusammen, && fügt zwischen den
beiden Zeichenketten ein Leerzeichen ein. Also
put "Mager" & "milch" into ergebnis
füllt den Container ergebnis mit "Magermilch",
während dagegen
put "Anton" && "Reiser" into name
der Variablen name die in diesem Fall sicher erwünschte
Zeichenkette "Anton Reiser" zuordnet.
Vielleicht haben Sie Lust, als Übung solch einen genetischen Algorithmus
zu programmieren.
Dawkins, Richard: Der blinde Uhrmacher, München (dtv) 1990
Eigen, Manfred und Ruthild Winkler: Das Spiel. Naturgesetze steuern den
Zufall, München/Zürich (Piper-Verlag) 1975
Reiser, Martin, und Niklaus Wirth: Programmieren in Oberon. Das neue Pascal,
Bonn (Addison-Wesley) 1994
|