Bitte Beachten: Dieser Blog wird hier nicht weiter geführt! Kommentare und neue Blogposts gibt es unter http://feitel.indeedgeek.de. Dort bitte auch neue Kommentare zu diesen Beiträge erstellen.

Dienstag, 27. November 2007

Schneckenalarm

Kennt ihr das wenn man von irgendeiner Aufgabe hört die eigentlich total trivial ist. Man weiß genau man hat keine Zeit. Aber man kann einfach nicht anders als diese Aufgabe jetzt und hier zu lösen und vergisst dabei alles andere um sich herum.

So ging es mir gestern wieder einmal. Unsere Erstsemester dürfen sich gerade mit der berühmt berüchtigten "Schnecke" herumschlagen. Ich musste das Programm auch schon im ersten Semester schreiben und muss sagen ist etwas Tricky. Ich habe das gestern so mit bekommen weil viele damit Probleme haben und nach einem Tipp gefragt haben.

Ich hab das ganze im Kopf durchgespielt und meinte: "Ach des sind nur 20 Zeilen Code...". Zuhause habe ich mir mein alten Code angeschaut und bin erschrocken. ich habe fast 200 Zeilen gebraucht und so beim darüber schauen erschien mir alles total kompliziert. Also was mach ich? Genau, ich hab mein Texteditor aufgemacht (noch nicht mal eclipse) und drauf los geschrieben.

Im ersten Semester weiß ich noch das ich mir Seitenweise Schnecken aufgemalt habe um zu verstehen wie sie funktionieren. Gestern waren es genau zwei Schnecken. Bei einer habe ich getestet wie es geht und bei der anderen überprüft. Man könnte ja sagen ich wusste ja schon wie es geht, allerdings habe ich nach einem anderen Ansatz gesucht als den vom ersten Semester.

Die Lösung soll übrigens so aussehen.

Das ganze hat einige erstaunliche Erfahrungen an den Tag gebracht und mir gezeigt das mein Studium vielleicht doch nicht ganz umsonst ist.

Vor allem aus der Vorlesung SEKS (Software Engineering komplexer Systeme) ist sehr viel in das Programm eingeflossen. Normalerweise würde man für das Problem ein zwei dimensionales Array nutzen und das immer über zwei Koordinaten ansprechen. Allerdings habe ich die Idee mit dem eindimensionalen Array aus SEKS geklaut und hier erstmalig angewendet. Prinzip ist: Wenn ich ein Feld nach rechts will addiere ich zur aktuellen Position eins hinzu. Für links wird eins subtrahiert. Für rauf wird die Größe des Arrays abgezogen und für runter das selbe darauf addiert. Also habe ich eine Matrix von 8x8 Feldern komme ich mit pos-8 nach oben und eben mit pos+8 nach unten. Das vereinfacht schon einmal viel da ich nicht immer mit zwei Koordinaten arbeiten muss sondern nur noch eine Position habe.

Auch von meiner Algo (Algorithmen und Datenstrukturen) floss viel in meine Schnecke ein. In Algo war immer eine sehr kurze und performante Lösung gefragt. Auch war es nicht ungewöhnlich das man einfach mal 30 Minuten vor 10 Zeilen sitzt und überlegt wie man das noch anders / einfacher gestalten kann.

Ich habe unbewusst meine Schnecke in mehrere Abschnitte unterteilt. Also zuerst Parameter von Außen geprüft und übernommen, dann Konstanten und anschließend Variablen definiert. Dann kam die eigentliche Ausführung gefolgt von der Ausgabe. Jeder dieser Teile habe ich glaub ich mehrmals neu geschrieben um jeden Teil für sich zu optimieren.

Hier erstmal der Code:

public class Schnecke {
  public static int aktuellerBuchstabe = 0;
  public static String[] output;
  public static String word;

  public static void main (String[] args) {
    if (args.length < 2) { System.err.println("Falsche Parameter"); System.exit(1); }
    int size = Integer.parseInt(args[0]);
    word = args[1];

    final int runter = size;
    final int rauf   = -size;
    final int links  = -1;
    final int rechts = 1;

    int height = size - 1;
    int width  = size - 1;
    int[] richtungen = {runter, links, rauf, rechts};
    output = new String[size * size];
    int pos = fill(size-1, 0, rechts);  // Da sich erster Schritt anders Verhällt

    while (height >= 1 && width >= 1) {
      for (int r : richtungen) {
        if (r == runter || r == rauf) { pos = fill(height, pos, r); height -=2; }
        else                          { pos = fill(width,  pos, r); width  -=2; }
        if (height < 1 || width < 1)  break;
      }
    }

    for(int i = 0; i < output.length; i++) {
      System.out.print((output[i] != null)? output[i]: " ");
      if (i % size == size-1 ) System.out.print("\n");
    }
  }

  public static int fill(int count, int pos, int richtung) {
    output[pos] = getNextChar();
    return (count == 0)? pos: fill(--count, (pos+richtung), richtung);
  }

  public static String getNextChar() {
    int pos = aktuellerBuchstabe++ % word.length();  // ++ sehr unschön
    return word.substring(pos, pos+1);
  }
}

Während der Implementierung sind mir wieder einmal die Grenzen von Java aufgefallen. Dadurch das es z.B. primitive Datentypen gibt stößt man schnell an die Grenzen des Machbaren. Deshalb habe ich mir schon vorgenommen das selbe Programm demnächst mit Ruby zu schreiben und mich überraschen zu lassen in wie weit sich das unterscheiden wird.

Mir ist durchaus bewusst das dieses Programm nichts tolles ist. Aber ich fand es gestern sehr interessant mir selbst beim Programmieren zu zuschauen. Viele interessante Dinge sind mir dadurch bewusst geworden. Bevor sich noch jemand beschwert, ich würde so komprimiert und mit so vielen kleinen Tricks nie etwas schreiben was ich öfters verwenden will, da es einfach zu undurchsichtig ist. Dann würde ich eher eine 200 Zeilen Variante bevorzugen. Diese Schnecke war einfach nur zum Testen gedacht.

4 Kommentare:

Anonym hat gesagt…

Snake coder... ;)

kb hat gesagt…
Dieser Kommentar wurde vom Autor entfernt.
nougad hat gesagt…

Bevor es noch einmal ein Missverständnisse gibt: Der Autor des Kommentars hat sein Kommentar gelöscht, nicht der Autor des Blogs. Ich zensier doch nicht mein eigenen Blog..

Anonym hat gesagt…

Genau so habe ich mir das auch gedacht, dass man im ersten Semester da umständlich und redundant arbeitet und denkt. Das Prinzip war, dass man versteht wie man was in einen Array und wieder raus bekommt