GameBoy-Adventures einfach entwickeln

Heute ist das dreißigjährige Jubiläum des GameBoy. Da wird der eine oder andere sicherlich nostalgisch an die gute alte Zeit zurückdenken. Nun kann auf dem GameBoy nicht nur gespielt werden was die Hersteller damals veröffentlichten, sondern auch eigene Entwicklungen für den GameBoy erstellt werden.

Das GB Studio unter macOS

Den meisten dürfte dies allerdings zu kompliziert sein. Schließlich ist der GameBoy aufgrund seiner begrenzten Ressourcen keine sonderlich einfache Umgebung. Mit dem GB Studio soll die Entwicklung trotzdem einfach möglich sein. Mithilfe des GB Studios ist es möglich grafische Adventure schnell und unkompliziert im Stil eines Game Makers zu erzeugen. Als Export-Formate werden ROMs und ein Web-Export unterstützt.

Das Spiele-ROM läuft im Emulator

Lizenziert ist GB Studio unter der MIT Lizenz. Da es auf Electron aufbaut, existieren Versionen für macOS, Linux und Windows. Der Quelltext des Projektes ist auf GitHub gehostet. Er ist unter der MIT-Lizenz lizenziert und damit freie Software. Die offizielle Seite des Projektes, auf der unter anderem die Dokumentation zu finden ist, ist unter gbstudio.dev zu finden.

Performance beim Ermitteln von Elementen aus einer Liste

Gestern schrieb ich einen Artikel über die Möglichkeiten ein Element aus einer Liste unter Java zu ermitteln. Dort wurde unter anderem eine Lösung mittels der Stream-API aufgezeigt. In einem Kommentar zu dem Artikel kam die Frage nach der Performance dieser Methode auf. Aus diesem Grund habe ich einen kleinen Benchmark geschrieben, welcher die Unterschiede in der Performance ermitteln sollte. Der Testfall bestand daraus ein Element aus einer Liste zu ermitteln. Dazu wird eine Liste mit knapp 125.000 Elementen erzeugt. Nun wurde mit unterschiedlichen Methoden versucht das entsprechende Element zu ermitteln. Das gesuchte Element befindet sich in den Testfällen immer an der Position 75.004 der Liste. Erzeugt wird die Liste mit der Methode getElements:

private List<Element> getElements() {

	List<Element> elements = new ArrayList<>();

	// Add 75000 elements
	for (int i = 0; i < 75000; i++) {
		elements.add(new Element(String.valueOf(i), String.valueOf(i)));
	}

	elements.add(new Element("Suppe", "Löffel"));
	elements.add(new Element("Wasser", "Flüssigkeit"));
	elements.add(new Element("Käse", "Gelb"));
	elements.add(new Element("Huhn", "Ei"));

	// Add 50000 elements
	for (int i = 0; i < 50000; i++) {
		elements.add(new Element(String.valueOf(i), String.valueOf(i)));
	}

	return elements;
}

Vom Gefühl her hätte ich vermutet, das die Stream-API immer langsamer ist als die klassische Iteration durch die Liste. Vier unterschiedliche Methoden wurden für das Benchmark implementiert. Beim Benchmark Iterate list wird die Liste über eine foreach-Schleife iteriert und beim entsprechenden Element abgebrochen:

for (Element element : elements) {

	if ("Huhn".equals(element.Key)) {
		specificElement = element;
		break;
	}
}

Die nächste Variante iteriert die Liste ebenfalls durch, nutzt aber die klassische Variante über den Index:

for (int j = 0; j < elements.size(); j++) {

	Element element = elements.get(j);

	if ("Huhn".equals(element.Key)) {
		specificElement = element;
		break;
	}
}

Anschließend folgt eine Variante über die Stream-API, bei welcher die Methode findFirst genutzt wird:

specificElement = elements.stream()
		.filter(element -> "Huhn".equals(element.Key))
		.findFirst()
		.orElse(null);

Bei der letzten Variante wird ebenfalls die Stream-API genutzt, nur diesmal wird findAny genutzt:

specificElement = elements.stream()
		.filter(element -> "Huhn".equals(element.Key))
		.findAny()
		.orElse(null);

Die Idee bei der Nutzung der Methode findAny ist, dass diese schneller ist, da die Suche theoretisch parallelisiert werden kann. Im JavaDoc zu der Methode wird das Ganze so beschrieben:

The behavior of this operation is explicitly nondeterministic; it is
* free to select any element in the stream. This is to allow for maximal
* performance in parallel operations; the cost is that multiple invocations
* on the same source may not return the same result.

Der Benchmark selber führt für jeden Testfall 75.000 mal durch, damit sich Ungenauigkeiten bei einzelnen Läufen wegmitteln und etwaige Optimierung zum tragen kommen können. Wird die Ausführungszeit über alle 75.000 Durchläufe betrachtet ergibt sich folgendes Bild:

Die Durchführungszeiten über alle Durchläufe

Bei der Betrachtung der einzelnen Durchläufe ergibt sich ein ähnliches Bild:

Die Durchführungszeiten pro Durchlauf

Die ermittelten Werte sehen wie folgt aus:

Iterate list
Time in seconds (total): 58.621323501
Time in seconds (per run): 0.00078161764668

Iterate list (without for each)
Time in seconds (total): 51.9264994
Time in seconds (per run): 0.0006923533253333333

Stream list and find first
Time in seconds (total): 55.3019915
Time in seconds (per run): 0.0007373598866666667

Stream list and find any
Time in seconds (total): 90.196209799
Time in seconds (per run): 0.0012026161306533333

Die schnellste Variante scheint die klassische Iteration über den Index zu sein, anschließend folgt die Variante mit der Stream-API und der Methode findFirst. Danach kommt die Iteration mittels einer foreach-Schleife und am Ende folgt weit abgeschlagen die Stream-API-Variante mit der Methode findAny. Das diese so schlecht abschneidet hat mich überrascht. Natürlich sollten Zahlen aus einem Benchmark immer mit Vorsicht genoßen werden, da es sich immer um eine künstliche Gegenüberstellung handelt. Das komplette Benchmark befindet sich auf GitHub und ist unter der MIT-Lizenz lizenziert und damit freie Software.

Java-Bibliothek für das Minecraft-Protokoll

Wenn sich der Minecraft-Client mit dem entsprechenden Server verbindet, so kommunizieren diese über ein festgelegtes Protokoll. Mit einer eigenen Implementation dieses Protokolls ist es möglich sich mit einem Minecraft-Server zu verbinden und entsprechende Aktionen durchzuführen. Zum Beispiel könnte diese Möglichkeit genutzt werden um einen Bot für Minecraft zu schreiben. Eine solche Implementation des Minecraft-Protokolls ist die Java-Bibliothek MCProtocolLib von Steven Smith.

Central City auf meinem eigenen Minecraft-Server

Ein minimales Beispiel, für den Login auf dem Server (basierend auf einem Unit-Test der Bibliothek), mit besagter Bibliothek könnte dabei wie folgt aussehen:

public class SimpleBot {

    private static final String HOST = "example.org";
    private static final int PORT = 25565;
    private static final Proxy PROXY = Proxy.NO_PROXY;
    private static final Proxy AUTH_PROXY = Proxy.NO_PROXY;
    private static final String USERNAME = "user@example.org;
    private static final String PASSWORD = "password";

    public static void main(String[] args) throws FileNotFoundException, RequestException {

        MinecraftProtocol protocol = new MinecraftProtocol(USERNAME, PASSWORD);
        Client client = new Client(HOST, PORT, protocol, new TcpSessionFactory(PROXY));
        client.getSession().setFlag(MinecraftConstants.AUTH_PROXY_KEY, AUTH_PROXY);

        client.getSession().addListener(new SessionAdapter() {
            @Override
            public void packetReceived(PacketReceivedEvent event) {
                if(event.getPacket() instanceof ServerJoinGamePacket) {
                    event.getSession().send(new ClientChatPacket("Hello, World!"));
                } else if(event.getPacket() instanceof ServerChatPacket) {
                    Message message = event.getPacket().getMessage();
                    System.out.println("Received Message: " + message.getFullText());
                    if(message instanceof TranslationMessage) {
                        System.out.println("Received Translation Components: " + Arrays.toString(((TranslationMessage) message).getTranslationParams()));
                    }

                    event.getSession().disconnect("Finished");
                }
            }

            @Override
            public void disconnected(DisconnectedEvent event) {
                System.out.println("Disconnected: " + Message.fromString(event.getReason()).getFullText());
                if(event.getCause() != null) {
                    event.getCause().printStackTrace();
                }
            }
        });

        client.getSession().connect();
    }
}

In diesem Beispiel wird sich mit dem Server verbunden und nach erfolgreicher Verbindung eine Chatnachricht gesendet. Danach loggt sich der Bot wieder aus. Der Quelltext der Bibliothek ist auf GitHub zu finden. Das Projekt ist unter der MIT-Lizenz lizenziert und damit freie Software.

Schriftarten zum Programmieren

Bei der Entwicklung von Software wird in den meisten Fällen ein wie auch immer gearteter Editor bzw. eine IDE genutzt. Innerhalb dieser IDE ist zur Darstellung des Quelltextes eine Monospace-Schriftart gesetzt. In einer solchen Schriftart sind alle Zeichen gleich breit. In folgendem Beispiel wird das deutlich:

www
iii

Sowohl das w als auch das i haben in einer Monospace-Schriftart die gleiche Breite. Bei der Entwicklung ist dies natürlich sehr praktisch, da dadurch der Quelltext an Übersichtlichkeit gewinnt. Jede IDE liefert in der Voreinstellung eine bestimmte Monospace-Schriftart mit. Soll diese Voreinstellung geändert werden, so findet sich eine große Auswahl an freien Monospace-Schriftarten im Netz. Die Programming Fonts-App erleichtert die Auswahl der passenden Schriftart.

In der App konnten die unterschiedlichen Schriftarten ausprobiert werden

In dieser App können die unterschiedlichen Fonts ausgewählt werden und in einem Editor schnell auf ihre Eignung geprüft werden. Der Quelltext der App ist auf GitHub zu finden. Lizenziert ist das Ganze unter der MIT-Lizenz und damit freie Software.

Datenbank ausprobieren leicht gemacht

Manchmal steht man vor dem Problem das eine Datenbank-Abfrage konstruiert werden soll, aber gerade keine Datenbank zur Hand ist. Auch für pädagogische Zwecke soll nicht gleich mit Kanonen auf Spatzen geschossen werden. Stattdessen bietet sich der Dienst SQL Fiddle an. SQL Fiddle selbst beschreibt sich wie folgt:

A tool for easy online testing and sharing of database problems and their solutions.

Im Dienst kann eine Datenbank definiert werden und diesen anschließend mit Werten befüllt werden. Nach der erfolgten Definition wird das Schema erzeugt und anschließend kann die Datenbank mit Abfragen getestet werden. Technisch wird bei jeder Schemageneration eine neue Datenbank erzeugt und für jede Abfrage wird eine Transaktion erzeugt, welche nach der Abfrage wieder zurückgerollt wird. Dadurch befindet sich die Datenbank immer in dem definierten Status.

Mit SQL Fiddle können Datenbankabfragen schnell getestet werden

Der Quelltext des Projektes ist auf GitHub zu finden. Er ist unter der MIT-Lizenz lizenziert und somit freie Software. Zu finden ist der Dienst unter sqlfiddle.com.