Algorithms

Aus hyperdramatik
Zur Navigation springen Zur Suche springen

Alle Snippets sind zunächst Pseudocode und je nach verwendeter Programmiersprache anzupassen.

Println() und Debug.Log() sind eure Freund*innen

Wenn ihr auf Probleme in eurem Code stosst, so vergewissert euch bitte, ob jeder Schritt bis zu eurem Problem hin auch so ausgeführt wird, wie ihr denkt. Der beste Weg das zu tun, ist durch die Nutzung von Println() bei Arduino und Processing, bzw. Debug.Log() bei unity. Lasst euch von euren Programmen ausgeben, was sie tun. Gleiches gilt für eure Annahmen, was Variablen angeht. Welchen Wert hat eine Variable in einem bestimmten Moment? Println() oder Debug.Log() the shit out of your code, so you know what's going on.

Checkliste "Mein Code funktioniert nicht"

  • Stimmen meine Semikola (";")?
  • Stimmen die Semikola in den darüber und darunterliegenden Zeilen?
  • Stimmen meine geschweiften Klammern ("{,}")- bei if-statements, bei funktionen, bei klassen?
  • Stimmen meine runden Klammern ("(,)")- rufe ich eine Funktion auf, muss eine runde Klammer dahinter?
  • Wird mein Code überhaupt ausgeführt (siehe Println() und Debug.Log BFF)?
  • Habe ich mich bei Variablennamen vertippt?
  • Wo habe ich meine Variable deklariert? Wenn innerhalb einer Funktion, dann gibt es die Variable nur innerhalb der Funktion, will ich das so?
  • Bei IF statements - kann ich mit papier und Stift nachvollziehen, was passieren soll?

Code ist Zustandsabfrage und Reaktion

Die allermeiste Zeit versuchen wir in Code einen bestimmten Zustand abzubilden, der dann von der Nutzerin verändert wird. Diese Veränderung des Zustands wollen wir abfragen, 'möglichst genau', und dann entsprechend in Code Dinge verändern. Beim strukturieren dieser verschiedenen Zustandsabfregen kann es irgendwann recht kompliziert werden, wenn wir alles miteinander in Kontext setzen. Hier ein paar Grundüberlegungen:

  • Wenn wir Code schreiben, der nach einer Nutzerinneneingabe reagiert, dann aber wieder in denselben Zustand zurückgeht, kommen wir mit einfachen 'if statements' zurecht. Beispiel: LED leuchtet wenn ein knopf gedrückt gehalten wird. Oder in Pseudocode:
if (/*ZustandsAbfrage*/){
  DoSomething();
}

  • Wenn wir Code schreiben, der verschiedene Zustände erreichen soll, und je nach Zustand etwas anderes tun soll, benutzen wir in einfachen Fällen 'boolean Variablen'. Beispiel: Wenn ein Schalter einmal gedrückt wurde, soll immer ein Licht an sein. Oder in Pseudocode:
bool bZustandErreicht;

if (/*Zustandsabfrage*/){
  bZustandErreicht = true;
}

if (bZustandErreicht){
  DoSomething();
}

Der Unterschied zwischen diesen beiden Codebeispielen ist folgender:

  • Im ersten Beispiel reagiert das Programm auf zwei Vorgänge. Wenn der Zustand, den wir durch die Zustandsabfrage abfragen eintritt (beispielsweise digitalRead(pin) bei Arduino), dann wird Code ausgeführt (beispielsweise digitalWrite(andererPin) bei Arduino). Und wenn der Zustand sich wieder ändert, also der Schalter nicht mehr gedrückt gehalten wird um bei unserem Beispiel zu bleiben, so wird auch der Code nicht mehr ausgeführt.
  • im zweiten Beispiel reagiert das Programm einmalig auf das drücken des Schalters. Die boolean Variable bleibt dann für immer (oder bis sie wieder durch anderen Code anders gesetzt wurde) in diesem Zustand. Sollte der Schalter losgelassen werden, ändert sich nichts.


Generell

Finde die Stelle mit der höchsten Zahl in einem Array von Zahlen

int höchsteZahl = -1000000;
int stelle = -1;

for (int i=0;i<arrayName.länge;i++){

 if (arrayName[i]>höchsteZahl){
   stelle=i;
   höchsteZahl=arrayName[i];
 }

}

Arduino

Führe eine Funktion einmalig aus, wenn ein Button gedrückt ist, und einmalig etwas anderes, wenn er losgelassen wird

int buttonDown =0;
int inputPin = 5; //hier muss der Pin eingetragen sein, an dem der Button hängt

[...]

void loop(){
  
  if (digitalRead(inputPin)==LOW){
    buttonDown++;
  }
  
  if (buttonDown==1){
     DoSomethingOnceWhenPressed();
  }

  if (digitalRead(inputPin)==HIGH && buttonDown>0){
    DoSomethingOnceWhenReleased();
    buttonDown=0;
  }
  
}

Mache etwas alle x-Durchläufe

int loopCounter=0;
int alleXLoops = 15; //Führt eine Funktion alle 15 loops aus
[...]

void loop(){
  
  loopCounter++;
  
  if (loopCounter%alleXLoops==0){
    DoSomethingEveryXLoops(); 
  }

}

Processing

Wie Ordne ich Dinge im zweidimensionalen Raum an (über Code)

  • Dazu benötigen wir einen Algorithmus, der eine gewisse Anzahl an Dingen in einem gewissen Platz mit dem gleichen Abstand anordnet.
    Das würde als Formel so aussehen: Abstand = (Platz - (Anzahl * Grösse)) / Anzahl

int x;

int Anzahl = 9;
int Platz = 400;
int Abstand = Platz/Anzahl;

void setup() {
  size(400, 400);
  background(215, 125, 2);
}

void draw() {
  for (int i=0; i < Anzahl; i++) {
    x= i * Abstand;
    rect(x, 40, 40, 40);
  }
}

Unity

Führe eine Funktion einmalig aus, wenn ein bestimmter Zustand erreicht ist

  • die ganz einfache Methode (sehr fehlerbehaftet, wenn zustand sich zwischen Frames nicht ändert):
public bool bZustand=false;

void Update(){

  if (/*ZustandsAbfrage*/){
    bZustand=true;
  }  

  if (bZustand){
    DoSomethingOnce();
    bZustand=false;
  }

}
  • bessere Variante ist, den Zustand als ganze Zahl, (noch besser als struct zu speichern), und die Funktion beim Zustandswechsel aufzurufen. Hier beispielweise, führen wir eine Funktion aus, wenn wir von Zustand 0 auf Zustand 1 übergehen:
public int zustand=0;

void Update(){

  if (/*Zustandsabfrage*/ && zustand != 1){
    DoSomethingOnce();
    zustand=1;
  }

}

Verändere die Position eines Objektes kontinuierlich entlang einer Achse

public GameObject meinObjekt //hier muss im Editor das Objekt das bewegt werden soll abgelegt werden

void Update(){
  meinObjekt.transform.position += new Vector3(xWert,yWert,zWert); 
}

Was ist ein IEnumerator und wann benutze ich ihn

Ein IEnumerator ist eine bestimmte Art von Funktion, die es erlaubt, Dinge über Zeit auszuführen. Ich benutze IEnumerator wenn ich:

  • eine längere Sequenz von Aktionen hintereinander ausführen will, die 'nicht' alle im selben Bild stattfinden sollen
  • eine bestimmte Zeit lang etwas ausführen möchte, z.b. ein Objekt 3 Sekunden lang nach oben bewegen
  • etwas nach einer bestimmten Zeit ausführen möchte, z.B. nach 15 Sekunden einen Ton abspielen will

IEnumerator werden oft ausgeführt, wenn ein bestimmter Zustand erreicht ist (z.B. ein Button geklickt, ein Trigger ausgelöst, eine Position erreicht, etc.)

Wie rufe ich eine IEnumerator Funktion auf

Für gewöhnlich werden Funktionen über ihren Funktionsnamen und die dazugehörigen Parameter aufgerufen: MeineFunktion(int ganzeZahl); Bei IEnumerator wird die Funktion über den Befehl "StartCoroutine" aufgerufen: StartCoroutine(MeineIEnumeratorFunktion(int ganzeZahl));

Was ist bei IEnumerator zu beachten

Auch IEnumerator können mehrfach ausgeführt werden und laufen dann Parallel.


Von einer Farbe über Zeit zu einer anderen wechseln, per IEnumerator

IEnumerator ChangeColor(){

  Color colornew = new Color();
  float t = 0;
  float amountOfSeconds = 4.0f;
  while (t < amountOfSeconds)
  {
     colornew = Color.Lerp(colorBegin, Color.magenta, t);
     GetComponent<Renderer>().material.color = colornew;
     
     t += Time.deltaTime/amountOfSeconds;
     yield return new WaitForEndOfFrame();
  }

}

Mit einem IEnumerator herausfinden ob etwas innerhalb einer Zeitspanne passiert ist

bool bPassiert=false;
float zeitraum = 4.0f // es wird innerhalb von 4 sekunden abgefragt ob ein zustand hergestellt wird

IEnumerator Abfrage(){

  float t=0.0f;
  while (t<zeitraum){
    if (/*Zustandsabfrage*/){
      bPassiert = true;  
    }
    
    t+=Time.deltaTime;
    yield return new WaitForEndOfFrame();
  }
 
}