Jump to content

Goetz

Mitglieder
  • Gesamte Inhalte

    6150
  • Benutzer seit

  • Letzter Besuch

Alle erstellten Inhalte von Goetz

  1. Beides geht. mit if … elseif … elseif … else bekommt man ein Konstrukt, dass sich genau wie case verhält. Und es ist auch nicht größer als eine case Liste. Die Schreibweise unterscheidet sich nur ein wenig. Bedingung = math.random(1,6) if Bedingung == 1 then print("Du hast eine 1 gewürfelt") elseif Bedingung == 2 then print("Du hast eine 2 gewürfelt") elseif Bedingung == 3 then print("Du hast eine 3 gewürfelt") elseif Bedingung == 4 then print("Du hast eine 4 gewürfelt") elseif Bedingung == 5 then print("Du hast eine 5 gewürfelt") else print("Du hast eine 6 gewürfelt") end Mit Tabellen bekommt man etwas viel besseres. Wenn man nämlich die einzelnen Fälle als Tabellenindex verwendet, dann kann man den vorliegenden Fall benutzen, um direkt dieses Tabellenelement anzuspringen. Man muss nicht vorher - wie bei case oder if … elseif - mehrere andere Fälle überspringen, bis man in der Aufzählung den passenden Fall gefunden hat. Und jedes Tabellenelement kann in Lua eine Funktion sein! Ausgaben = { [1] = function() print("Du hast eine 1 gewürfelt") end, [2] = function() print("Du hast eine 2 gewürfelt") end, [3] = function() print("Du hast eine 3 gewürfelt") end, [4] = function() print("Du hast eine 4 gewürfelt") end, [5] = function() print("Du hast eine 5 gewürfelt") end, [6] = function() print("Du hast eine 6 gewürfelt") end } Bedingung = math.random(1,6) Ausgaben[Bedingung]()
  2. Kurze Meldung zum laufenden Lua Tutorial: Ich brauche bitte eine kurze Pause, bevor ich die nächsten Kapitel posten kann. Im Übrigen freue ich mich ganz enorm, dass das Interesse so konstant ist. Die letzten Postings in der Serie wurden ebenso oft abgerufen wie die ersten. Teils sogar häufiger (vermutlich, weil der Eine oder Andere noch einmal etwas nachlesen will.) Insgesamt wird das trotzdem kein vollständiges Lua-Tutorial werden. Das würde meines Erachtens den Rahmen sprengen. Ich wollte euch gerne anhand von Beispielen an die Sprache sowie das Programmieren im Allgemeinen heranführen. Ich möchte euch die Systematik zeigen, die alledem zugrunde liegt. Und dazu habe ich noch ein paar weitere Kapitel geplant, für die ich aber etwas Zeit benötige.
  3. But of course. A condition leads to a branch in the execution of code. Therefor, one or the other action happens right after the condition has been evaluated. Just like a car would show up at either side of an intersection at the same time after passing the fork in the road..
  4. Tabellen - Teil 6 Für den Aufruf von Funktionen, die in einer Tabelle stehen, kennt Lua noch einen besonderen Trick. Und der macht das Anlegen von Funktionen innerhalb von Tabellen erst sinnvoll. Man kann die Adresse der Tabelle beim Aufruf der Funktion als Argument mitgeben. Damit ist es selbst bei tief gestaffelten Tabellen ein Leichtes, direkt auf Elemente der Tabelle zuzugreifen, in der auch die Funktion steht. Ich möchte etwas weiter ausholen, um die Zusammenhänge möglichst durchschaubar zu machen. Als Beispiel soll noch einmal die Zugtabelle aus dem vorletzten Kapitel dienen: Zuege = { { Name = "Gueterzug_1", Geschwindigkeit = 80, Typ = "Gueter", Lok = { Name = "V200", Typ = "Diesel", Kupplung_vorne = false, Kupplung_hinten = true }, Waggons = { { Name = "G10", Typ = "Kasten", Kupplung_vorne = true, Kupplung_hinten = true }, { Name = "Kbs", Typ = "Rungen", Kupplung_vorne = true, Kupplung_hinten = true }, { Name = "OVP", Typ = "Tank", Kupplung_vorne = true, Kupplung_hinten = true }, { Name = "G10", Typ = "Kasten", Kupplung_vorne = true, Kupplung_hinten = false }, } } } Zuege enthält die Adresse der ganzen Tabelle Zuege[1] enthält die Adresse der ersten Untertabelle (in der alle Daten des ersten Zuges stehen) Zuege[1].Waggons enthält die Adresse der Untertabelle mit allen Waggons in der Untertabelle 1 der Tabelle Zuege. Zuege[1].Waggons[1] enthält die Untertabelle mit den Details des ersten Waggons innerhalb der Untertabelle aller Waggons innerhalb … Solche Adressen kann man an eine neue Variable übergeben: Dings = Zuege[1].Waggons[1] Das ist dann sinnvoll, wenn man anschließend diese Adresse mehrfach benötigt. Weil es die Schreibweise der Adressen innerhalb dieser Untertabelle jetzt vereinfacht Dings.Name Dings.Typ Dings.Kupplung_vorne Selbstverständlich wählt man im Ernstfall einen sinnvolleren Namen als „Dings“. Nun stellt euch bitte vor, dass in der Untertabelle eines Waggons eine Funktion enthalten ist, die etwas mit den Daten dieses Waggons tut. Die zum Beispiel den Namen und den Typ des Waggons ausgibt (um die Geschichte jetzt nicht ausufern zu lassen.) Dann würde man beim Aufruf der Funktion die gesamte Adresse innerhalb der Tabelle mit angeben. Zuege[1].Waggons[1].Ausgabe() Jetzt könnte man die Adresse außerdem als Argument mitgeben: Zuege[1].Waggons[1].Ausgabe( Zuege[1].Waggons[1] ) Für dieses Argument legt man in der Funktionsdefinition eine Variable an. Ein gebräuchlicher Name für diese Variable ist „self“. Aber jeder andere Name funktioniert genauso gut. Zuege[1].Waggons[1].Ausgabe = function(self) print("Mein Name ist "..self.Name.." und ich bin vom Typ "..self.Typ) end Das ist ungemein praktisch, weil es die Adressierung der Daten innerhalb dieser Tabelle so bequem macht. Die komplette Adresse der Untertabelle wird an die lokale Variable self übergeben. Also muss man innerhalb der Funktion nur noch self schreiben, wenn man Zuege[1].Waggons[1] meint Und das ist noch nicht alles. Ich kann die identische Funktion für alle Waggons benutzen, weil ich nur die jeweils passende Adresse als Argument an self übergeben muss. Und deshalb hat man in Lua die Schreibweise für den Funktionsaufruf vereinfacht. Programmierer mögen es nämlich nicht, wenn sie etwas doppelt schreiben müssen. Weil es das Risiko vergrößert, sich dabei zu verschreiben. In Lua kann man die Adresse an einer Stelle mit einem Doppelpunkt anstelle des einfachen Punkts aufteilen. Zuege[1].Waggons[1]:Ausgabe() Dann wird automatisch alles, was vor dem Doppelpunkt steht, als erstes Argument übergeben. Werte, die man in die Klammern schreibt, sind damit die Argumente 2 bis … Der Grund, warum ich diesen relativ schweren Stoff in einem Einsteiger-Tutorial anspreche, ist folgender: Die einzelnen Objekte im MBS werden mit V5 fertige Lua Funktionen enthalten. Und der Aufruf dieser Funktionen wird dem folgenden Muster entsprechen: Objektname:Funktionsname(Argumente) Das Objekt hat eigene Daten. Und diese wird die Funktion des Objekts verwenden. Wenn die Funktion ein Signal umstellen soll, dann wird sie dafür die Achsen der Signalflügel ansprechen. Wenn man an einem Kran einen Haken anheben kann, dann muss die Funktion dafür ebenfalls die entsprechenden Parameter des Krans ansprechen und verändern. Wie das im Einzelnen passiert, ist für uns unwichtig. Die Funktion ist in V5 ja fertig definiert. Die Definition müssen wir nicht selbst entwerfen. Aber der Funktionsaufruf wird diesen Gesetzmäßigkeiten folgen. Wir schreiben möglicherweise so etwas wie: Kran:Haken(0) um den Haken in Nullstellung zu bringen. Wie das konkret aussieht, weiß ich auch erst wenn der Beta-Test der V5 beginnt. Mir geht es jetzt ausschließlich darum, dass ihr anhand meiner generischen Beispiele das zugrundeliegende Prinzip durchschaut. Weil dann verständlicher wird, warum was in welcher Reihenfolge im Befehl stehen muss und was es mit dem Doppelpunkt im Funktionsaufruf auf sich hat. Darüber hinaus könnt ihr euch dieses Wissen natürlich auch in eurem eigenen Programmcode zunutze machen. Denn alles, was man rund um den Eisenbahnverkehr steuert, lässt sich wunderbar tabellarisch verwalten. Es lohnt sich wirklich, die Lua-Tabellen zu durchschauen und den Umgang damit zu üben. Weil man tabellarisch später auch sehr komplexe Situationen gut und überschaubar in den Griff bekommt.
  5. Tabellen - Teil 5 Ihr habt nun gesehen, dass man in einer Tabelle Zahlen, Strings, Booleans und Tabellen speichern kann. Und das letzte Beispiel hat euch vielleicht gezeigt, warum das praktisch ist. Es geht bei Tabellen nur darum, eine Ansammlung von Daten vernünftig zu organisieren. Das ist ungefähr so, als würde man alles, was zu einem bestimmten Waggon gehört, in eine Schachtel packen: Seinen Namen, die Beschriftungen, die Länge, den Status der beiden Kupplungen, die Position beweglicher Teile etc. Und dann einen Zug bilden, indem man eine Lok-Schachtel und mehrere Waggon-Schachteln hintereinander in eine große Zug-Schachtel steckt. Das hat alles nur organisatorische Bedeutung. @wopitir schrieb mir gestern eine PN, in der er die ganze Tabellenstruktur mit den Ordnern und Unterordnern bei Windows verglich. Und das trifft es ganz gut. Aber Lua Tabellen können noch mehr. Man kann in einer Tabelle auch eine Funktion speichern. Warum auch nicht? Man speichert in Lua ja eigentlich nur die Adressen, unter denen etwas liegt. Ob an dieser Speicheradresse eine Zahl, ein Text oder eine Funktionsdefinition zu finden ist, macht technisch also gar keinen Unterschied. Vorweg muss ich eine alternative Schreibweise für die Definition einer Funktion vorstellen. Diese Variante kennt ihr schon: function Beispiel() print("Ich bin eine Beispielfunktion") end Diese Schreibweise macht dasselbe: Beispiel = function() print("Ich bin eine Beispielfunktion") end Der einzige Unterschied ist die Reihenfolge, in der etwas passiert. Im zweiten Beispiel wird zuerst eine namenlose Funktion angelegt und dann die Adresse dieser Funktion an den Namen Beispiel übergeben. Das Resultat ist aber dasselbe wie bei der ersten Schreibweise. Die zweite Schreibweise eignet sich, um die Adresse einer Funktion an einen Tabellenplatz zu übergeben: Bands = { Beatles = {"John", "Paul", "George", "Ringo"}, Stones = {"Mick", "Keith", "Brian", "Ian", "Bill", "Charlie"}, Who = {"Pete", "Roger", "John", "Keith"}, Anzahl = function(Bandname) print("Die Band "..Bandname.." hat "..#Bands[Bandname].." Mitglieder") end, Erster = function(Bandname) print("Das erste Bandmitglied der "..Bandname.." heißt: "..Bands[Bandname][1]) end } Bands.Anzahl("Stones") Bands.Erster("Who") Beachtet bitte, dass innerhalb der Funktion keine Kommas am Zeilenende stehen dürfen. Denn der gesamte Funktionsblock bildet ein Element. Am Ende der Funktionsdefinition muss hingegen zwingend ein Komma stehen, falls weitere Tabellenelemente folgen. Deshalb steht im obigen Beispiel ein Komma hinter dem end, welches die Definition von Anzahl abschließt. Im MBS sind die Modelle Objekte. Und diese Objekte werden, wenn ich Neo richtig verstanden habe, in V5 eigene Funktionen bekommen, welche man per Lua aufrufen kann. Wie ihr oben seht, ist der Aufruf solcher Funktionen sehr einfach. Aber es hilft wenn man eine Vorstellung davon hat, wie die Daten dazu tabellarisch organisiert sind.
  6. Tabellen - Teil 4 Eine Lua Tabelle kann Elemente vom Typ 'table' enthalten Beispiel = { {1, 2, 3} , {63, 127, 255} , {true, true, false} } Das Ergebnis hat Ähnlichkeit mit mehrdimensionalen Tabellen. Die 63 im obigen Beispiel steht an Position Beispiel[2][1], nämlich im zweiten Block an erster Stelle. Der Vergleich mit landläufigen Tabellen ist aber irreführend. Hilfreicher ist, die Lua-Tabellen einfach als Datensammlung zu verstehen. Sie haben in mancher Hinsicht mehr Ähnlichkeit mit Objekten als mit Tabellen. Deshalb müssen Lua-Tabellen nicht dimensioniert werden. Das heißt, dass man nicht (wie in anderen Sprachen) vorher die Anzahl der Zellen festlegen muss. Bands = { Beatles = {"John", "Paul", "George", "Ringo"}, Stones = {"Mick", "Keith", "Brian", "Ian", "Bill", "Charlie"}, Who = {"Pete", "Roger", "John", "Keith"} } print(Bands.Stones[2]) Die Tabelle Bands enthält 3 Elemente, deren Index jeweils ein String ist. Nämlich der Bandname. Jedes der drei Elemente ist ebenfalls eine Tabelle. Die Elemente dieser Untertabellen sind einfache Aufzählungen. Der Index jedes Elements ist also eine Nummer, beginnend mit der Zahl 1 für das erste Element. Beachtet bitte das Komma hinter jeder Untertabelle. Dieses Komma ist erforderlich, um die Elemente Beatles, Stones und Who voneinander zu trennen. Die Zeilenumbrüche und Einrückungen in der Tabelle sind optional und dienen nur der Lesbarkeit. Man könnte ebenso gut den gesamten Tabelleninhalt in eine lange Zeile schreiben. Oder umgekehrt auf noch mehr Zeilen verteilen: Bands = { Beatles = { "John", "Paul", "George", "Ringo" }, Stones = { "Mick", "Keith", "Brian", "Ian", "Bill", "Charlie" }, Who = { "Pete", "Roger", "John", "Keith" } } Das ist reine Geschmacksache. Die Trennung der Elemente entsteht allein durch die Kommas und die geschweiften Klammern. Aber aus Erfahrung kann ich empfehlen, Programmzeilen mit mehr als 80 Zeichen Länge zu vermeiden. Im Übrigen werdet ihr im MBS keine großen Tabellen am Stück erstellen. Dazu besteht kein Grund. Diese Tabellen entstehen auf andere Weise. Aber es wird euch helfen, wenn ihr versteht wie Tabellen in Lua aufgebaut sind. Weil ihr später an einzelne Daten aus solchen Tabellen drankommen wollt. Weil ihr zum Beispiel von einem Zug den Namen des dritten Waggons benötigt: Zuege = { { Name = "Gueterzug_1", Geschwindigkeit = 80, Typ = "Gueter", Lok = { Name = "V200", Typ = "Diesel", Kupplung_vorne = false, Kupplung_hinten = true }, Waggons = { { Name = "G10", Typ = "Kasten", Kupplung_vorne = true, Kupplung_hinten = true }, { Name = "Kbs", Typ = "Rungen", Kupplung_vorne = true, Kupplung_hinten = true }, { Name = "OVP", Typ = "Tank", Kupplung_vorne = true, Kupplung_hinten = true }, { Name = "G10", Typ = "Kasten", Kupplung_vorne = true, Kupplung_hinten = false }, } } } print(Zuege[1].Waggons[3].Name)
  7. Tabellen - Teil 3 Der Index eines Tabellenelements darf in Lua auch ein String sein. Man kann die Zellen also mit Namen versehen: Farbe = {} Farbe["Rot_Anteil"] = 128 Farbe["Gruen_Anteil"] = 64 Farbe["Blau_Anteil"] = 0 Die Anführungszeichen um den Namen sind erforderlich, damit Lua an dieser Stelle Zellennamen von Variablen unterscheiden kann. In einer vereinfachten Schreibweise hängt man den Index nach einem Punkt an den Tabellennamen. Bei dieser Schreibweise dürfen keine Anführungszeichen verwendet werden. Farbe = {} Farbe.Rot_Anteil = 128 Farbe.Gruen_Anteil = 64 Farbe.Blau_Anteil = 0 Das ist gut lesbar und bequemer zu schreiben. In der Bedeutung ist es mit der ersten Schreibweise identisch. Ebenso kann man namentliche Indexe gleich bei der Initialisierung verwenden: Farbe = {["Rot_Anteil"] = 128, ["Gruen_Anteil"] = 64, ["Blau_Anteil"] = 0} oder in der vereinfachten Schreibweise: Farbe = {Rot_Anteil = 128, Gruen_Anteil = 64, Blau_Anteil = 0} Bitte beachten: Diese vereinfachten Schreibweisen sind ausschließlich für Strings geeignet. Eine Nummer als Zellenindex muss in eckigen Klammern stehen. Ein Variablename ebenfalls. Nummeriete und namentlich bezeichnete Zellen dürfen in derselben Tabelle vorkommen: Band = {"John", "Paul", "George", "Ringo", Name = "Beatles"} print("Die "..Band.Name.." sind: "..Band[1]..", "..Band[2]..", "..Band[3].." und "..Band[4]) Zur Erinnerung: Mit einem # vor dem Tabellennamen bekommt man den Index vor der ersten Lücke im durchnummerierten Teil einer Tabelle. Im vorliegenden Beispiel liefert #Band also den Wert 4. Die Zelle "Name" wird nicht mitgezählt. Die Funktionen table.insert() und table.remove() verlangen als Index eine Nummer. Sie können nicht auf namentlich indizierte Zellen angewendet werden. Möchte man eine Zelle löschen, dann weist man ihr den Wert nil zu. Das funktioniert mit jedem Index. Ist der Index eine Zahl, dann werden die nachfolgenden Zellen nicht verschoben und es entsteht eine Lücke in der Nummerierung.
  8. Tabellen - Teil 2 Möchte man wissen, wieviele Elemente sich in einer Tabelle befinden, dann kann man diese Zahl mit einem # vor dem Namen der Tabelle bekommen: Beispiel = {"Eins", "Zwei", "Drei"} Anzahl = #Beispiel Man kann in Lua eine leere Tabelle anlegen Beispiel = {} Und anschließend Elemente hinzufügen Beispiel[1] = "Eins" Beispiel[2] = "Zwei" Bei dieser Methode werden keine Elemente verschoben. Eventuell vorhandene Elemente werden überschrieben. Wenn man den Index angibt, unter dem Elemente gespeichert werden sollen, sind Lücken in der Liste möglich Beispiel[5] = "Fünf" #Beispiel gibt in diesem Fall den Index vor der ersten Lücke zurück. Das wäre im vorliegenden Beispiel eine 2 Im folgenden Beispiel wäre es eine 5, obwohl die Elemente 1 und 2 nicht existieren und das letzte Element den Index 7 hat. Beispiel = {} Beispiel[3] = "Drei" Beispiel[4] = "Vier" Beispiel[5] = "Fünf" Beispiel[7] = "Sieben" print(#Beispiel) Man kann Tabellen wahlweise nutzen um sortierte, durchnummerierte Listen zu erstellen oder um Elemente an bestimmte Nummern wie z.B. IDs zu knüpfen. Da Lua beides im selben Typ 'table' verwaltet, muss man selbst darauf achten, die beiden Fälle richtig zu unterscheiden. Für Änderungen an durchnummerierten Listen gibt es unter anderem die Funktionen table.insert(Tabelle, Index, Wert) und table.remove(Tabelle, Index) Lässt man bei table.insert() den Index weg (zwei Parameter statt drei), hängt es den neuen Wert dort an, wo in der Liste die erste Lücke gefunden wird. Nachfolgende Elemente verschieben sich nicht! Damit fungiert es als append, welches Lua nicht als eigenständige Funktion bietet. Beispiel = {} Beispiel[3] = "Drei" Beispiel[4] = "Vier" Beispiel[5] = "Fünf" Beispiel[9] = "Neun" table.insert(Beispiel, "Sechs") for i = 1, 10 do print(i.." - ", Beispiel[i]) end Die Funktion table.remove() liefert den entfernten Wert als Ergebnis zurück. Beispiel = {"Eins", "Zwei", "Drei", "Vier", "Fünf", "Sechs"} for i = #Beispiel-1, 1, -1 do table.insert(Beispiel, table.remove(Beispiel, i)) end for i = 1, #Beispiel do print(i.." - "..Beispiel[i]) end
  9. Tabellen - Teil 1 Variablen bieten die Möglichkeit, einen Wert unter einem Namen abzulegen. Oftmals ist es aber sinnvoll, mehrere Werte unter einem einzelnen Namen zusammenzufassen, weil sie in irgendeiner Weise zusammengehören. Koordinaten zum Beispiel. Oder Farbwerte. Oder Personendaten. Oder alle Parameter einer Lok (Name, Geschwindigkeit, Ort …) Für diesen Zweck bietet Lua Tabellen. Und in Lua gibt es nur Tabellen. Andere Programmiersprachen kennen außerdem Listen, Dictionaries, Tupfes und mehr. Lua fasst das alles in einem Typ 'table' zusammen. Tabellen werden mit geschweiften Klammern erzeugt. Koordinaten = {0, 0, 0} und die Elemente einer Tabelle werden durch ein Komma getrennt. Die geschweiften Klammern findet man auf einer normalen, deutschen PC-Tastatur mit AltGr 7 und AltGr 0 Die einzelnen Elemente einer Tabelle sind indiziert. Das bedeutet, dass sie durchnummeriert sind. Und dass man sie über diese Nummer ansprechen kann. Den Index eines Tabellenelements schreibt man bei Lua in eckige Klammern Koordinaten[1] Die eckigen Klammern findet man auf einer normalen, deutschen PC-Tastatur mit AltGr 8 und AltGr 9 Eine Lua Tabelle darf Elemente unterschiedlichen Typs enthalten Person = {"Max", "Mustermann", 182, 3.5, true} Diese Tabelle enthält zwei Strings, eine Ganzzahl, eine Fließkommazahl und ein Boolean. Das erste Element einer Tabelle hat den Index 1 Person[1] == "Max" Darin unterscheidet sich Lua von allen anderen Programmiersprachen! Für den Einsteiger ist diese Nummerierung sehr angenehm, weil sie seinen Erwartungen entspricht. Für routinierte Programmierer ist sie eine Falle, weil sie den bisherigen Gewohnheiten widerspricht. Für die Lesbarkeit darf man beliebig viele Leerzeichen einfügen. Farbe = {0, 32, 128} und Farbe = { 0, 32, 128} sind identisch. Ebenso darf man Zeilenumbrüche einfügen um die Lesbarkeit zu verbessern Texte = { "Eine Lok steht auf Gleis 1", "Der Güterzug wurde abgefertigt", "Der Weg für den Schnellzug ist frei", "Der Schattenbahnhof ist voll!" } Das Komma als Trennzeichen zwischen den Elementen ist auch bei mehrzeiliger Schreibweise zwingend erforderlich. Hinter dem letzten Element ist ein Komma optional. Man darf es schreiben, aber Lua verlangt es nicht.
  10. Ja. Das Schlüsselwort dafür heißt break Wenn du einen for-Schleifenzähler über die Schleife hinaus noch benötigst, musst du ihn - genau wie du vermutest - übergeben. Was du im while ... do Konstrukt stehen hast, ist kein Zähler, sondern eine Bedingung. Ob du diese Bedingung innerhalb der While Schleife durch Zählen oder anderweitig veränderst, macht keinen Unterschied. Die Variable wird nicht in der Bedingung erzeugt und ist nicht automatisch local.
  11. Variablen für Fortgeschrittene Lua Variablen können ohne Deklaration Daten jeden Typs speichern. Und man kann auch beim Überschreiben von Werten den Typ ändern. Ich kann beispielsweise eine Zahl mit einem String überschreiben, ohne dass Lua meckert. Das geht deshalb, weil in den Variablen selbst gar kein Wert steht, sondern nur eine Speicheradresse. Die Variable speichert nur, wo etwas steht aber nicht, was dort steht. Und Adressen sind immer gleich lang. Egal, ob sie auf eine Zahl, einen String oder etwas anderes zeigen. Variablen sind in Lua immer global definiert. Man muss ihnen bei der Deklaration das Schlüsselwort local voran stellen, um lokale Variablen zu erzeugen. function Test_a() a = 1 return a end function Test_b() local b = 1 return b end if Test_a() == a then print("a ist eine globale Variable") else print("a ist eine lokale Variable") end if Test_b() == b then print("b ist eine globale Variable") else print("b ist eine lokale Variable") end Funktionsargumente und Schleifenzähler sind automatisch lokale Variablen Lua erlaubt multiple Zuweisungen a, b = 2, 3 Damit lassen sich auch Werte tauschen: a, b = b, a Wenn man mehrere Variablen zugleich deklariert, dann kann man allen zusammen einmal das Schlüsselwort local voranstellen local a, b, c = 1, 2, 3
  12. Variablen im 3D-Modellbahn Studio Im MBS gibt es Daten, die man als User gerne auslesen und verwenden möchte. Zum Beispiel die Stellung eines Signals. Oder die Geschwindigkeit einer Lok. Oder der Name des Fahrzeugs auf einem Gleisstück. Damit man in der EV an diese Daten kommt, haben die Speicherplätze für diese Daten eigene Namen. Das sind also Variablen, deren Name schon im MBS festgelegt wurde. Wenn man davon absieht, dass die Namen dieser Speicherplätze schon festliegen und die Werte in diesen Speicherplätzen vom MBS stammen, unterscheiden sich diese Variablen nicht von solchen, die man selbst deklariert. Es sind Speicherplätze, die einen Namen bekommen haben, damit man sie im Programmcode oder in der EV verwenden kann. Ein Teil der Schwierigkeiten, welche manche User mit Variablen haben, stammen möglicherweise von den Namen dieser Variablen. Man muss die richtigen Namen kennen. Und das sind vielleicht nicht die Namen, welche man selbst ausgesucht hätte. An dieser Tatsache wird auch Lua nichts ändern. Wenn eine Person „Peter“ heißt, dann muss ich sie mit „Peter“ ansprechen. Auch, wenn ich finde, dass der Name „Klaus“ viel besser passen würde. Peter fühlt sich nur angesprochen, wenn ich ihn mit seinem Namen anrede. Welche MBS-Variablen es in V5 geben wird, weiß ich nicht. Aber sie werden eine wichtige Rolle spielen, weil man auch mit Lua die MBS Objekte steuern will. Das geht nur, wenn ich die Namen der einzelnen Objektparameter kenne. In Lua Skripten werden sowohl Variablen vorkommen, die vom MBS stammen als auch solche, die man selbst definiert. Und die müsst ihr unterscheiden können. Ihr müsst verstehen, wann ihr euch an vorgegebene Namen halten müsst und wann ihr eigene Namen definiert. Das ist nicht schwer. Es muss einem nur bewusst sein, dass es diesen Unterschied gibt.
  13. Variablen Bislang habe ich den Variablen kein eigenes Kapitel gewidmet. Normalerweise fängt man ein Tutorial damit an, dass man Variablen erklärt. Aber ich weiß, dass manche hier Abneigungen verspüren, wenn dieses Thema aufkommt. Und man müsste Variablen abstrakt und ohne passenden Zusammenhang erklären, wenn man ein Tutorial mit diesem Thema beginnt. Deshalb hatte ich mich für eine andere Reihenfolge entschieden. In den ersten Übungen habt ihr Variablen schon benutzt. Ihr habt sie kennengelernt, ohne dass ich sie im Detail erklärt habe. Und ihr habt schon den Zusammenhang gesehen, in dem man Variablen einsetzt. Variablen sind nichts anderes als Platzhalter. Wenn ich beim Entwurf einer Funktion bestimmte Inhalte noch nicht kenne, dann schreibe ich Platzhalter dorthin, wo später diese Inhalte eingesetzt werden sollen. Und damit ist im Prinzip schon erklärt, was eine Variable ist. Mehr steckt nicht dahinter. Man kann Variablen einen beliebigen Namen geben. Der darf aus einem einzelnen Buchstaben bestehen oder ein ganzes Wort sein. Aber der Name darf nur aus Buchstaben, Ziffern und dem Unterstrich bestehen. Und er darf nicht mit einer Ziffer beginnen. (Ich hatte das in einem früheren Kapitel schon einmal geschrieben. Aber es ist so wichtig, dass ich es hier noch einmal wiederholen möchte.) Vermeidet spezielle Buchstaben wie z.B. Umlaute oder das ß. Sicher kennt ihr von E-Mails das Problem, dass an Stelle solcher Buchstaben manchmal kryptische Zeichenfolgen auftauchen? Dasselbe könnte euch auch im Programmcode passieren und dann für Probleme sorgen.
  14. Lösungsbeispiele „Differenz21“ Beginnen möchte ich wieder mit dem Lösungsweg, der die Aufgabe „buchstäblich“ umsetzt: function Differenz21(n) Ergebnis = math.abs(21 - n) if n > 21 then Ergebnis = Ergebnis * 2 end return Ergebnis end Zuerst wird die Differenz von 21 und n gebildet und der Betrag dieser Differenz in einer Variablen Ergebnis gespeichert. Dann wird geprüft, ob n größer als 21 ist. Falls ja, dann wird der Wert in Ergebnis verdoppelt und wieder in Ergebnis gespeichert. Zuletzt wird der Wert von Ergebnis ausgegeben. Es wäre sauberer, Ergebnis als eine lokale Variable anzulegen. Aber mit der globalen Variable funktioniert das Skript ebenso gut. Drum habe ich mehr Wert auf ein leicht lesbares Beispiel gelegt. Unter anderem sollte dieses Beispiel dazu dienen, die math.abs() Funktion vorzustellen. Die ist praktisch und mit einem einfachen Beispiel, wie dem hier gezeigten, leicht zu verstehen. Aber für die gestellte Aufgabe kommt man auch ohne diese Funktion aus. function Differenz21(n) Ergebnis = 21 - n if n > 21 then Ergebnis = Ergebnis * -2 end return Ergebnis end Das Ergebnis von 21 - n kann ja nur dann negativ sein, wenn n größer als 21 ist. Und wenn man in diesem Fall das Ergebnis sowieso verdoppeln muss, dann kann man es auch mit -2 multiplizieren, um aus dem negativen einen positiven Wert zu machen. Damit entfällt die Notwendigkeit, den Betrag der Differenz zu bilden. Außerdem ist eine Überlegung wert, ob man den ursprünglichen Wert von n im weiteren Verlauf behalten muss. Falls nicht, dann kann man die Variable n selbst verändern und wieder auszugeben. function Differenz21(n) n = 21 - n if n < 0 then n = n * -2 end return n end Man spart so eine zusätzliche Variable ein. Und n ist, wie alle Funktionsargumente, eine lokale Variable. Es ist riskant, den Wert der ursprünglichen Variable zu ändern. Schnell übersieht man dabei, dass man den ursprünglichen Wert später noch benötigt. Im vorliegenden Fall für den Vergleich, ob n größer als 21 ist. Das letzte Beispiel funktioniert nur, weil ich diesen Vergleich durch einen anderen ersetzt habe. Denn wenn n größer als 21 war, dann ist das Ergebnis von 21 - n kleiner als 0. Alternativ kann man auch erst prüfen, ob n größer als 21 ist und dann entsprechend verzweigen function Differenz21(n) if n > 21 then return (n - 21) * 2 end return 21 - n end Durch den Tausch der beiden Werte in der Subtraktion entfällt in der dritten Zeile das negative Vorzeichen vor dem Multiplikator. Der Einzeiler für Fortgeschrittene kann so aussehen: function Differenz21(n) return n > 21 and (n - 21) * 2 or 21 - n end Ich hoffe, ihr hattet Spaß an diesen Knobeleien? In den nächsten Kapiteln will ich wieder ein paar Grundlagen zu Lua erklären.
  15. Differenz21 In dieser Aufgabe hat die zu definierende Funktion nur einen Parameter vom Typ "number". Ich gebe der Variable den Namen n. Die Funktion soll den absoluten Wert der Differenz zwischen 21 und n zurückgeben. Und falls n größer als 21 ist, soll dieser Wert verdoppelt werden. Als absoluten Wert bezeichnet man die positive Version einer Zahl. Ein anderer Ausdruck für den absoluten Wert ist "Betrag". Der Betrag von 5 ist 5 Der Betrag von -5 ist ebenfalls 5 Beispiele: Für n = 1 muss die Funktion den Wert 20 ausgeben Für n = 25 muss die Funktion den Wert 8 (das doppelte des Betrags von -4) ausgeben function Differenz21(n) end Lua bringt eine vordefinierte Funktion mit, die den Betrag einer Zahl bildet. Diese Funktion heißt math.abs() und ist eine von mehreren Funktionen aus der "math" Bibliothek. Deshalb hat sie diesen zweiteiligen Namen mit dem Punkt dazwischen. Dazu erkläre ich in späteren Kapiteln mehr. Ein Skript mit Prüfroutine hänge ich wieder an dieses Posting an. Viel Spaß beim Ausprobieren und Studieren. Differenz21.zip
  16. für Fortgeschrittene In Lua sind Variablen grundsätzlich global definiert! Mit Ausnahme der Funktionsargumente, die selbstverständlich lokale Variablen sind. Möchte man eine lokale Variable erzeugen, dann muss man dafür in Lua das Schlüsselwort local benutzen. Richtig müsste mein letztes Beispiel aus dem vorherigen Posting also lauten: function Wurf(a, b) local c = a + b if a == b then c = 2 * c end return c end Eine lokale Variable gilt nur innerhalb der Funktion und wird bei Verlassen gelöscht. Die Verwendung lokaler Variablen innerhalb von Funktionsdefinitionen vermindert das Risiko von Namenskonflikten (weil der Namensbereich auf die Funktion und ihre Unterfunktionen beschränkt ist) spart Speicherplatz (weil der Platz für diese Variable nach Verlassen der Funktion frei gegeben wird) beschleunigt das Programm (weil diese kurzlebigen Variablen im Prozessor-nahen Speicher angelegt werden.) Für die letzte Aufgabe gibt es noch einen weiteren, interessanten Lösungsweg. Er macht sich das besondere Verhalten von and und or zunutze, welches ich im Kapitel 2b or not 2b angesprochen hatte. function Wurf(a, b) return a == b and 4 * a or a + b end Wenn a == b wahr ist, dann ist das Ergebnis der and Verknüpfung der zweite Term 4 * a Und weil dieser Term auf jeden Fall wahr ist, wird der Term hinter dem or nicht mehr geprüft, sondern das Resultat der and Verknüpfung ausgegeben. Nämlich 4 * a, ganz wie gewünscht. Ist die erste Bedingung hingegen nicht wahr, dann ist das Ergebnis der and Verknüpfung auch nicht wahr. Und in diesem Fall wird der Term ausgegeben, der hinter dem or steht. Nämlich a + b. Dieser Weg ist kein bisschen schneller als die zuvor gezeigten. Das ist nur eine akademische Spielerei, die aber mächtigen Spaß machen kann und zu mehr Routine führt.
  17. Lösungsbeispiele zu "doppelte Summe" Zuerst möchte ich einen Lösungsweg zeigen, den ich häufig sehe. Er setzt den Aufgabentext "buchstäblich" um: function Wurf(Zahl_1, Zahl_2) if Zahl_1 == Zahl_2 then return (Zahl_1 + Zahl_2) * 2 else return Zahl_1 + Zahl_2 end end Wenn die beiden Zahlen gleich sind, dann bilde die Summe, vedopple sie und gib das Ergebnis aus. Andernfalls gib einfach die Summe der beiden Zahlen aus. Beachtet bitte, dass bei der Verdopplung in der dritten Zeile die Summe in Klammern stehen muss. In Lua gilt Punktrechnung vor Strichrechnung. Das heißt, dass ohne die Klammern nur die zweite der beiden Zahlen verdoppelt würde. Hier ist ein Vorschlag zur Vereinfachung des obigen Beispiels: In der zweiten Zeile wird geprüft, ob beide Zahlen gleich sind. Und die dritte Zeile wird nur dann ausgeführt, wenn diese Bedingung erfüllt war. Also ist Zahl_1 + Zahl_2 an dieser Stelle dasselbe wie Zahl_1 + Zahl_1 oder 2 * Zahl_1. Deshalb kann man die Rechenoperation in Zeile 3 vereinfachen. function Wurf(Zahl_1, Zahl_2) if Zahl_1 == Zahl_2 then return 4 * Zahl_1 else return Zahl_1 + Zahl_2 end end Ein weiterer Weg wäre der, dass man zuerst eine der beiden Zahlen ändert, falls beide gleich sind. Und dann die Summe bildet. function Wurf(Zahl_1, Zahl_2) if Zahl_1 == Zahl_2 then Zahl_1 = 3 * Zahl_1 end return Zahl_1 + Zahl_2 end Für das Ergebnis macht dieser unorthodoxe Weg keinen Unterschied. Man kommt damit genauso schnell und sicher zum Ziel wie mit den ersten beiden Wegen. Aber diese Fassung ist schwer nachvollziehbar und deshalb nicht wirklich ratsam. Trotzdem haben mir solche Gedankenexperimente geholfen, Lua und überhaupt das Programmieren besser zu verstehen. Deshalb möchte ich euch gerne dazu animieren, solche verschiedenen Lösungswege durchzuspielen. Mit diesen sehr einfachen Aufgaben, die nur wenige Zeilen Programmcode erfordern, kann man das gut machen. Die folgende Methode ist populär und gut lesbar: function Wurf(Zahl_1, Zahl_2) Ergebnis = Zahl_1 + Zahl_2 if Zahl_1 == Zahl_2 then Ergebnis = 2 * Ergebnis end return Ergebnis end Diesmal wird das Ergebnis in mehreren Schritten gebildet und in einer neuen Variable namens Ergebnis zwischengespeichert. Lua kann diese Variable gleich in der Funktion bilden. Man muss sie nicht erst deklarieren, wie das vor allem bei Compiler-Sprachen erforderlich ist. Man weist der Variablen einfach einen Wert zu und kann sie anschließend verwenden. Selbstverständlich kann diese Variable jeden beliebigen Namen haben und muss nicht zwingend Ergebnis heißen. Und genauso kann man übrigens auch die Namen der Funktionsargumente ändern. Diese Variablen existieren ja nur innerhalb der Funktion. Man kann das letzte Beispiel also auch so schreiben: function Wurf(a, b) c = a + b if a == b then c = 2 * c end return c end Dem einen oder anderen ist diese Schreibweise vielleicht einleuchtender. Weil die Formeln besser zutage treten. Nur den Namen der Funktion solltet ihr bitte beibehalten, wenn ihr mein kleines Testskript verwenden wollt. Denn das ist der Funktionsname, der weiter unten mit verschiedenen Beispielwerten aufgerufen wird.
  18. Du findest Lua in sehr vielen Spielen wie z.B. Minecraft oder Factorio. Meines Wissens eignet es sich besonders gut für diese Art der Integration in Programme. Und es ist - wie Python - sehr Einsteiger-freundlich. https://en.wikipedia.org/wiki/List_of_applications_using_Lua#Video_games
  19. doppelte Summe Die dritte Aufgabe hat dasselbe Muster wie die vorherigen beiden. Aber die beiden Parameter beim Aufruf sind diesmal keine booleans (true oder false), sondern Zahlen. Die Funktion soll die Summe der beiden Zahlen zurückgeben. Und wenn beide Zahlen gleich sind, dann soll sie die Summe vor der Ausgabe verdoppeln. function Wurf(Zahl_1, Zahl_2) end Ich habe die Funktion "Wurf" genannt, weil die Aufgabe für ein Würfelspiel geeignet wäre. Der Spieler würde per Knopfdruck zwei Zahlen würfeln und die Funktion, welche ihr hier definiert, errechnet dann das Ergebnis. Ein Pasch zählt dabei doppelt. Im Anhang findet ihr wieder ein Skript mit angehängter Testroutine, welches ihr für die Prüfung eurer Lösungsansätze verwenden könnt. Ich freue mich über jeden Lösungsvorschlag, den ihr mir als Nachricht schickt. doppelte Summe.zip
  20. Ich glaube, für eine ehrliche Antwort muss sich niemand entschuldigen. Und Lua muss dich nicht erschrecken. Weil es nicht erforderlich ist, dass man das lernt. Die V5 wird dir gewiss auch ganz ohne Lua viel Freude machen. Und du wirst auch ohne Lua Kenntnisse auf nichts verzichten müssen. Lua ist einfach nur eine weitere Möglichkeit der Anlagensteuerung und für diejenigen gedacht, denen diese Methode liegt. Es ist wie ein weiteres Musikinstrument. Man muss nicht alle Instrumente beherrschen, um Musik zu machen. Aber man kann eine größere Auswahl an Musik genießen, wenn alle Musiker viele verschiedene Instrumente zur Auswahl haben.
  21. Stimmt. Das wüsste ich auch zu gerne. Motiviere ich die Leser? Oder verschrecke ich sie eher?
  22. Lösungsvorschläge für das Affentheater In dieser Aufgabe war, genau wie in der ersten, gefordert, dass die Funktion etwas zurückgeben soll. Und zwar soll sie true zurückgeben, wenn beide Parameter true sind. Wenn also beide Affen grinsen. Und die Funktion soll auch dann true zurückgeben, wenn beide Parameter false sind. Wenn also beide Affen nicht grinsen. Das kann man genau so in die Funktion schreiben: function Schwierigkeiten(Kaya_grinst, Toto_grinst) if Kaya_grinst and Toto_grinst then return true end if not Kaya_grinst and not Toto_grinst then return true end return false end Und weil die erste und die zweite Bedingung dieselbe Konsequenz haben, kann man sie auch in einer Bedingung zusammenfassen. function Schwierigkeiten(Kaya_grinst, Toto_grinst) if (Kaya_grinst and Toto_grinst) or (not Kaya_grinst and not Toto_grinst) then return true end return false end Beachtet bitte, dass in der Mitte ein or steht und kein and. Denn es reicht ja, wenn einer der beiden geklammerten Ausdrücke wahr ist. Umgangssprachlich würde man in der Mitte ein "und" benutzen: "Wenn beide Affen grinsen gib ein true zurück und wenn beide nicht grinsen, dann auch." Aber logisch wäre ein and die falsche Wahl, weil es bedeutet, dass beide Bedingungen zugleich erfüllt sein müssen. Weil jetzt der gesamte Ausdruck hinter dem if genau das ergibt, was wir als Antwort brauchen, kann man ihn auch direkt zurück geben: function Schwierigkeiten(Kaya_grinst, Toto_grinst) return Kaya_grinst and Toto_grinst or not Kaya_grinst and not Toto_grinst end Dabei kann man sogar die Klammern weglassen, weil das and stärker bindet als das or und das not stärker bindet als das and. Das heißt: Zuerst führt Lua die beiden not Operationen durch, dann die and Operationen und zuletzt die or Operation. Diese Schreibweise ist aber furchtbar unleserlich. Die erste Version mit den zwei einzelnen Prüfungen finde ich in diesem Punkt deutlich angenehmer. Deshalb habe ich überlegt, ob man die nicht noch etwas vereinfachen kann. Nehmen wir den Fall, dass Kaya grinst. Dann ist das gewünschte Ergebnis true, wenn Toto_grinst true ist. Und es ist false, wenn Toto_grinst false ist. Wir können also auf die and Verknüpfung verzichten und gleich Toto_grinst zurückgeben, falls Kaya_grinst wahr ist if Kaya_grinst then return Toto_grinst end Und wenn man auch für den Fall etwas definieren möchte, dass die Bedingung hinter dem if nicht erfüllt ist, dann gibt es in Lua dafür das Schlüsselwort else (zu Deutsch: "andernfalls" oder "sonst") Und was soll andernfalls passieren? Was ist als Ergebnis gefordert, wenn Kaya nicht grinst? Falls Toto_grinst jetzt true ist, dann ist das Ergebnis false. Falls aber Toto_grinst auch false ist und somit beide Affen nicht grinsen, dann ist das Ergebnis true. Für den Fall, dass Kaya nicht grinst, ist das Ergebnis also das Gegenteil von Toto_grinst. Es ist not Toto_grinst function Schwierigkeiten(Kaya_grinst, Toto_grinst) if Kaya_grinst then return Toto_grinst else return not Toto_grinst end end Verblüfft? Man kann sich aber auch ganz vom genauen Wortlaut der Aufgabe lösen und stattdessen schauen, was wirklich gefordert ist: Wenn beide Affen dasselbe tun, dann ist das Ergebnis wahr, sonst nicht. Dann müsste es doch auch genügen, wenn man die beiden Parameter vergleicht. function Schwierigkeiten(Kaya_grinst, Toto_grinst) return Kaya_grinst == Toto_grinst end Das funktioniert, ist wirklich gut lesbar und außerdem schön schlank. Vielen Dank @Andy für diese sehr schöne Einsendung. Ich hoffe, dass mit dieser zweiten Aufgabe noch deutlicher wird, was schon bei der ersten Aufgabe durchschien: Dass es nicht darum geht, für eine Aufgabe eine richtige Lösung zu finden. Und sich diese Lösung dann für die Zukunft zu merken. Das funktioniert einfach nicht. Es geht vielmehr darum, möglichst viele dieser Lösungsbeispiele zu durchschauen. Zu erkennen, was da jeweils im Code passiert und warum das funktioniert. Je klarer euch anhand der verschiedenen Beispiele wird, wie die Mechanismen funktionieren, desto leichter wird es euch fallen Skripte zu entwerfen, die zu euren konkreten Bedürfnissen passen. Und deshalb mag ich diese kleinen Übungen so sehr. Man kann anhand dieser Beispiele wunderbar demonstrieren, welche Denkansätze alle zum Ziel führen. Man kann die verschiedenen Lösungsvorschläge mit der eigenen Lösung vergleichen und vielleicht an der einen oder anderen Stelle denken: "Ah - der Weg ist auch nicht schlecht." Und man kann unterschiedliche Methoden sehr bequem ausprobieren. Viel Spaß bei euren Entdeckungen. Die dritte Aufgabe folgt morgen.
  23. Affentheater Die zweite Aufgabe ist der ersten sehr ähnlich. Diesmal geht es um die Affen Toto und Kaya, welche uns gerne Schwierigkeiten bereiten. Aber man kann es ihnen ansehen. Wenn beide grinsen oder wenn keiner von beiden grinst, dann stecken wir in Schwierigkeiten. Grinst einer der beiden Affen, aber der andere nicht, dann haben wir nichts zu befürchten. Der Funktionsrahmen sieht so aus function Schwierigkeiten(Kaya_grinst, Toto_grinst) end Die Funktion wird wieder mit zwei Parametern aufgerufen werden, die beide entweder true oder false sein können. Und sie soll true zurückgeben, wenn wir in Schwierigkeiten stecken oder false, falls nichts zu befürchten ist. Das Prinzip ist also dasselbe wie bei der vorherigen Aufgabe. Die möglichen Kombinationen aus true und false sollen nur diesmal zu anderen Ergebnissen führen. Deshalb muss man die beiden Parameter anders auswerten als beim ersten Mal. Im Anhang findet ihr wieder ein Skript mit angehängter Testroutine für die Prüfung eurer Lösungsansätze. Ich würde mich sehr freuen, wenn ihr mir eure Lösungsvorschläge per PN schickt. Affentheater.zip
  24. Lösungsansätze zur Aufgabe "Ausschlafen" Wenn man mein Testskript unverändert in das Lua-Demo Fenster kopiert, dann bekommt man diese Antwort: Das Programm wird fehlerfrei ausgeführt. Es enthält keine Syntaxfehler. Aber die Funktion tut noch nicht das, was sie tun soll. Weil die Funktion völlig leer ist, gibt sie auch nichts zurück. Und genau das steht in der Auflistung. Viermal ergeben die Parameter nil. Sie sollten aber in drei Fällen true und in einem Fall false ergeben. Was passiert, wenn man in die Funktion einfach return true schreibt? function Ausschlafen(Werktag, Urlaub) return true end Dann ist das Ergebnis nur noch in einem von vier Fällen falsch. Mit return kann man also dafür sorgen, dass die Funktion beim Aufruf etwas zurück gibt. Jetzt muss man dafür sorgen, dass sie abhängig von den beiden Argumenten Werktag und Urlaub das richtige zurück gibt. Wenn Urlaub wahr ist, dann muss die Funktion ein true zurückgeben. Denn dann kann man ausschlafen. Das könnte so aussehen function Ausschlafen(Werktag, Urlaub) if Urlaub then return true end end Beachtet bitte, dass man in der if ... then Zeile keinen Vergleich Urlaub == true benötigt. Denn dieser Vergleich liefert nur das, was in Urlaub schon drin steht. Ist Urlaub wahr, dann ist auch das Ergebnis des Vergleichs wahr. Ist Urlaub falsch, dann ist auch das Ergebnis des Vergleichs falsch. Der zusätzliche Vergleich erfordert zusätzliche Rechenzeit, bringt aber keinen Nutzen. Wenn man diese Funktion verwendet, dann ist das Ergebnis in zwei von vier Fällen falsch. Die Funktion gibt nil zurück, wenn Urlaub nicht wahr ist. Ist Urlaub wahr, dann ist das Ergebnis der Funktion richtig. Nun kann man den Werktag prüfen: function Ausschlafen(Werktag, Urlaub) if Urlaub then return true end if Werktag then return false end end Damit ist das Ergebnis schon in drei von vier Fällen richtig. Nur wenn kein Urlaub und kein Werktag ist, lautet das Ergebnis noch nil. Denn weder die erste, noch die zweite Bedingung ist erfüllt. Deshalb gibt die Funktion nichts zurück. Sie soll in diesem Fall aber true zurückgeben, weil man ausschlafen kann wenn kein Werktag ist. function Ausschlafen(Werktag, Urlaub) if Urlaub then return true end if Werktag then return false end return true end In dieser Form besteht die Funktion alle 4 Tests Dazu muss man wissen, dass ein return in einer Funktion dazu führt, dass die Funktion komplett verlassen wird. Alles, was nach dem return kommt, ignoriert Lua wenn die return Zeile ausgeführt wird. Deshalb wird der Werktag nicht mehr geprüft, wenn Urlaub wahr ist. Und deshalb wird die letzte Zeile nicht mehr ausgeführt, wenn Urlaub falsch, aber Werktag wahr ist. Das bedeutet, dass bei dieser Konstruktion die Reihenfolge wichtig ist. Wenn man sie vertauscht, dann erhält man zum Teil falsche Ergebnisse. function Ausschlafen(Werktag, Urlaub) if Werktag then return false end if Urlaub then return true end return true end Bei dieser Reihenfolge würde der Urlaub nicht mehr geprüft, wenn Werktag wahr ist. Der Wecker klingelt jetzt auch im Urlaub an Werktagen. Denn die erste Prüfung hat an Werktagen zur Folge, dass die Funktion sofort mit einem return false verlassen wird Jetzt kehrt die Prüfung bei Werktag bitte einmal ins Gegenteil. Testet, ob kein Werktag ist. function Ausschlafen(Werktag, Urlaub) if not Werktag then return true end if Urlaub then return true end return false end Das heißt, dass jetzt true zurückgegeben wird, wenn kein Werktag ist. Und wenn kein Werktag ist, dann ist es egal, ob Urlaub ist oder nicht. Und false wird nur dann zurückgegeben, wenn weder die erste, noch die zweite Bedingung erfüllt ist. Bei dieser Variante sind die beiden Prüfungen austauschbar. Und außerdem kann man sie jetzt in einer Prüfung zusammenfassen. function Ausschlafen(Werktag, Urlaub) if not Werktag or Urlaub then return true end return false end Und weil der gesamte Term not Werktag or Urlaub jetzt genau das ergibt, was wir als Antwort haben wollen, muss man auch keine if-Prüfung mehr durchführen. Man gibt einfach das Ergebnis der logischen Verknüpfung zurück function Ausschlafen(Werktag, Urlaub) return not Werktag or Urlaub end Manche setzen den Term hinter dem return in Klammern, weil andere Programmiersprachen das so fordern. In Lua ist das nicht erforderlich, aber erlaubt. Ich weiß, dass das alles abstrakt und für Einsteiger eine harte Nuss ist. Deshalb poste ich in den nächsten Tagen weitere Übungen dieser Art. Denn diese kleinen Beispiele enthalten im Kern genau das, was man auch für die Nutzung von Lua im MBS brauchen wird. Funktionen, die anhand von Parametern eine Entscheidung treffen und dann das eine oder andere tun. Es wird vermutlich Funktionen geben, die fertig definiert sind und nur mit geeigneten Parametern aufgerufen werden. So wie das bekannte print(). Und es wird vermutlich die Möglichkeit geben, aus der EV eine Funktion aufzurufen, die man an anderer Stelle selbst definiert. Ich weiß das nicht. Aber es ist sehr naheliegend, dass es so sein wird. Deshalb halte ich es für sinnvoll euch anhand kleiner Beispiele das grundlegende Prinzip zu zeigen. Und ich hoffe natürlich, dass ihr auch ein bisschen Spaß dabei habt.
  25. @m.weber Danke für deine offenen Worte. Jetzt verstehe ich besser, warum ich angeeckt bin. Gruß Götz
×
×
  • Neu erstellen...