1. showCube()

Andrey, Arman und ich haben uns als Projekt überlegt, einen Roboter zu programmieren, der den Rubik’s Cube (3x3x3-Zauberwürfel) löst.

Wir haben auf http://mindcuber.com eine Bauanleitung für einen solchen Roboter gefunden, die die Lego Mindstorms Education Sets verwendet.

Ich habe mich vor allem mit dem Teil des Projekts beschäftigt, in dem es darum geht, den Algorithmus zum Lösen des Würfels zu schreiben.

Um die Lego-Roboter zu programmieren, verwenden wir im Projektkurs eine API für Java.

Ich habe meinen Teil des Programms allerdings erst einmal in Swift geschrieben, weil ich dadurch die Möglichkeit hatte, mit SceneKit eine kleine iOS-App zu programmieren, die den Würfel dreidimensional anzeigt.

Da Swift und Java beides objektorientierte Programmiersprachen sind, sind sie sich ohnehin sehr ähnlich und der Aufwand, das Programm in Java umzuschreiben, war am Ende dann auch nicht mehr so groß.

Bevor ich jedoch mit meinem Teil des Programms anfangen konnte, mussten wir uns als Gruppe darauf festlegen, wie wir den Würfel im Programm überhaupt speichern wollen.

Ein Teil des Projekts besteht darin, dass der Roboter den Würfel (mit dem Farbsensor des Lego Mindstorms Education Sets) scannt. Dieses Ergebnis wird an den Teil des Programms übergeben, der dafür verantwortlich ist, den Würfel zu lösen (mein Part). Für diese Übergabe ist es wichtig, dass wir einheitlich programmieren.

Ein Würfel, der an das Programm übergeben wird, könnte z.B. so aussehen:

Würfel (3D)

Es liegt nahe, den Würfel im Code durch ein 3x3x3-Array darzustellen.

Allerdings wird es schnell sehr kompliziert, wenn es beispielsweise darum geht, was das Drehen der Seiten des Würfels im Dreidimensionalen bedeutet.

Um das zu umgehen, stellen wir uns den Würfel einfach zweidimensional als Würfelnetz vor.

(Es hat sich im Laufe des Projekts herausgestellt, dass das, was hier scheinbar eine Vereinfachung ist, das Programm an vielen Stellen eher umständlich und redundant macht. Aber dazu später mehr.)

Würfelnetz  (2D)

Auf dem Bild kann man erkennen, wie wir die einzelnen kleinen Farbflächen des Würfels systematisch durchnummeriert haben.

Zudem haben wir entschieden, die Farben zum Speichern durch die Zahlen von 0 bis 5 zu ersetzen. Für die Logik, die hinter dem Würfel steckt, ist es nicht relevant, welche Farben der Würfel hat. Und es gibt ja auch Würfel, die nicht die Standardfarben (wie im Bild) haben; trotzdem wird der Würfel auf die gleiche Art gelöst.

Wir verwenden nun ein eindimensionales Integer-Array der Größe 54, um dieses Würfelnetz im Code darzustellen.

Die Formatierung als Würfelnetz geht dabei verloren, stattdessen schreiben wir die Zahlen, die die verschiedenen Farben beschreiben, hintereinander, so wie es auf diesem Bild zu sehen ist:

Array (1D)

(Die Farben hier sollen nur verdeutlichen, wie unsere Darstellung als Array mit der Darstellung als Würfelnetz und als 3D-Würfel zusammenhängt. Am Ende besteht das Array nur aus den Zahlen 0, 1, 2, 3, 4 und 5, die jeweils 9 mal darin vorkommen.)

Zu Beginn meines Programms ist der Würfel noch gelöst und hat dann als Array dargestellt diese Form: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, …, 2, …, 3 …, 4 …, …, 5].

So sieht der Code aus, um dieses Array in Java bzw. Swift zu erstellen:

Java
Swift

In der ersten Zeile wird jeweils eine Variable „array“ erstellt, die ein leeres Array vom Typ Integer (ganze Zahl) zugewiesen bekommt.

In Java muss man die Größe, die das Array später haben soll, von Anfang an angeben und sie kann danach nicht mehr verändert werden, während Arrays in Swift keine feste Größe haben.

Das Füllen des Arrays mit den Zahlen funktioniert daher auch etwas unterschiedlich. In Swift kann man die Methode append() verwenden und so mit zwei verschachtelten for-Schleifen die Zahlen 0 bis 5 jeweils 9 mal an das leere Array anhängen.

Die innere for-Schleife sieht in Java etwas anders aus, denn hier muss man die genauen Positionen im Array angeben, an die die Zahlen hinzugefügt werden sollen.

Man kann das Array in Swift z.B. einfach in der Konsole ausgeben und erhält dann folgende Ausgabe:

Ich habe zunächst eine Methode geschrieben, die das Array wieder als Würfelnetz formatiert ausgibt:

Hierfür habe ich ein paar Hilfsmethoden geschrieben:

  • getFace() gibt einen Teil des des Arrays zurück, für die obere Seite z.B. [0, 0, 0, 0, 0, 0, 0, 0, 0].
  • getLine() und getColumn() geben einzelne Zeilen und Spalten einer Seite zurück.
  • Mit setLine() und setColumn() können einzelne Zeilen und Spalten einer Seite überschrieben werden (Diese Methoden sind später für das Drehen der Seiten erst wichtig).
  • Mit Hilfe von printLine() wird jeweils eine Zeile formatiert in der Konsole ausgegeben, die aus bis zu 4 kleineren Teilen, einzelnen Zeilen der Seiten, bestehen kann.