Samstag, 27. Dezember 2014

Schneller, schneller

Mit den letzten Updates von Sechzehn habe ich in drei Schritten die Performance verbessert.

  1. Den größten Performanceschub brachte die Verlagerung der Berechnung eines neuen Spieles in die Datenbank. Neuerdings wird die Lösung eines Spieles von einer Stored Procedure erledigt. Denn wenn viele gültige Wörter im Spielfeld gefunden werden konnten, dauerte die Neuberechnung eines Spieles durchaus über 30 Sekunden. Das führte dann zu Timeouts in der Anwendung. Die aktuelle Variante ist bis zu 100 mal schneller.
  2. Den für den Anwender spürbarsten Performanceschub bringt der Wechsel des HTTP-Servers. Ich habe den Webrick durch den Puma ersetzt. Im Gegensatz zum Webrick kann Puma mehrere Anfragen parallel bearbeiten. Dadurch kommt es nicht mehr für alle Spieler zu Verzögerungen, wenn jemand die Highscoretabellen durchblättert, oder gerade ein neues Spiel berechnet wird. Die Bedienung von Sechzehn fühlt sich jetzt insgesamt flüssiger an.
  3. Die dritte Änderung betrifft das Chat-Fenster. Dies habe ich auf Websockets umgestellt. Damit entfällt die Notwendigkeit, dass jeder Spieler alle fünf Sekunden auf dem Server nach neuen Nachrichten schaut. Stattdessen wird an alle Clients ein Ereignis gesendet, sobald irgendwer eine neue Nachricht schreibt. Damit entfallen eine Menge Anfragen an den Server, der dadurch mehr Zeit für das eigentliche Spiel übrig hat.

    Ein kleiner Wermutstropfen bleibt hier allerdings. Der Dienst, den ich für die Auslieferung von Nachrichten nutze (es ist Pusher), erlaubt in der kostenlosen Variante nur 20 gleichzeitige Verbindungen. Falls sich herausstellt, dass regelmäßig mehr Spieler online sind, werde ich den Chat nur für registrierte Spieler freigeben. Noch habe ich das Limit aber bei weitem nicht erreicht.

Natürlich sind mit den letzten Updates auch einige Fehler behoben worden. Die meisten betrafen lediglich das Layout des Spiels. Einer betraf den Buchstaben q. Der Fehler hat sich eingeschlichen, als das Spielfeld von <div> auf <canvas> umgestellt wurde. Damit der Pfad der getippten Buchstaben nachzeichnet werden kann, musste einiges an Javascript neu geschrieben werden. Dabei habe ich die Sonderbehandlung des q übersehen. Da dieser Buchstabe auch nur sehr selten im Spielfeld erscheint, ist der Fehler erst vor kurzem aufgefallen.

Montag, 17. November 2014

Endlich ein Chatfenster

Schon sehr bald nachdem ich Sechzehn live geschaltet hatte, haben sich Spieler bei mir gemeldet, die gerne ein Chat-Fenster gehabt hätten. Nun, nach gut sechs Monaten ist es so weit. Die Spieler können während und nach einer Runde Sechzehn miteinander chatten. Es werden keine Chatprotokolle mitgeschrieben. Alles was älter als eine halbe Stunde ist, fliegt automatisch aus der Datenbank raus. Außerdem ist es mit Ruby on Rails leider nicht möglich einen Echtzeit-Chat zu realisieren. Stattdessen aktualisiert sich das Chat-Fenster alle fünf Sekunden, bzw. sobald man selber eine Nachricht abgesetzt hat.

Ich werde die Serverlogs von Sechzehn jetzt eine Weile beobachten. Wenn die Antwortzeiten des Spiels unverhältnismäßig ansteigen sollten, werde ich das Chatfenster wieder entfernen. Im Moment schaut es jedoch noch recht gut aus.

Samstag, 15. November 2014

Öfter mal was Neues

Sechzehn läuft nun schon einige Monate recht stabil. Allerdings mussten einige kleinere Schwächen ausgeräumt werden.

Zum Einen wuchs mir so langsam die Pflege der Datenbank über den Kopf. Leider darf diese nämlich aus Kostengründen nicht mehr als 20 Millionen Datensätze enthalten. Daher bin ich gezwungen, regelmäßig alle Lösungen und erratenen Wörter aus der Datenbank zu löschen. Das macht jetzt ein nächtlicher Job, den man auf Heroku ohne Zusatzkosten einrichten kann. Einfach einen Rake-Task aufsetzen und vom Scheduler täglich zu einer bestimmten Uhrzeit ausführen lassen - bingo. Hätte ich gewusst, wie einfach das ist, hätte ich den Scheduler schon von Anfang an genutzt.

Die Andere Änderung an Sechzehn betrifft die Art und Weise wie das Spielerranking errechnet wird. Die Rechenvorschrift bleibt in Zukunft die gleiche. Allerdings werden jedem Spieler, der mehr als 24 Stunden nicht gespielt hat, jede Nacht vier Punkte von seiner ELO-Zahl abgezogen. Dies bedeutet, dass ein Spieler, der lediglich ein einziges Mal Sechzehn gespielt hat, nach circa einem Jahr seine 1600 ELO Punkte aufgebraucht hat. Spieler, die nur noch Null Punkte übrig haben, verschwinden aus der Highscore Liste, können aber jederzeit wieder mit dem Spielen anfangen.

Dienstag, 1. April 2014

Realisierung - Multiplayer

Der Singleplayer-Modus von Sechzehn war inzwischen fertig. Man konnte bereits ein Spiel erzeugen, drei Minuten lang Wörter raten, und nach Spielende die Auswertung und die Lösung begutachten. Das Layout des Spiels entsprach zu diesem Zeitpunkt schon dem, was man heute sehen kann. Nun galt es also, Sechzehn zum Multiplayer Spiel zu machen.

Multiplayer


Das Ruby on Rails Framework wartet auf Browseranfragen, führt dann eine Funktion aus, und liefert das Ergebnis - meistens HTML - an den anfragenden Browser zurück. Danach wartet Ruby on Rails auf die nächste Browseranfrage. Es gibt also keinen Spieleserver der kontinuierlich im Hintergrund alle paar Minuten ein neues Spiel erzeugt. Vielmehr muss die Erzeugung des nächsten Spieles von außen angestoßen werden.

Meine Lösung besteht darin, dass ich mir für jedes Spiel merke, wann es erzeugt wurde. Wenn ein Spieler Sechzehn spielen möchte, schau ich erst nach, wie alt das letzte Spiel ist. Ist es jünger als drei Minuten, kann der Spieler sofort für die Restdauer des Spieles mitspielen. Ist das letzte Spiel aber älter als drei Minuten, dann wird ein neues Spiel berechnet. Sollte in der Zeitspanne, in der ein neues Spiel errechnet wird, ein zweiter Spieler ebenfalls feststellen, dass das letzte Spiel älter als drei Minuten ist, wird dieser gebeten, in einer Sekunde noch einmal nachzufragen, ob das neue Spiel bereits fertiggestellt ist.

Auf diese Weise ist immer ein Spiel vorhanden, an dem alle gerade aktiven Spieler gemeinsam teilnehmen können. Das Multiplayer-Modus Problem war gelöst.


Freitag, 28. März 2014

Realisierung - Spielfeld berechnen

Die Featureliste war erstellt. Jetzt konnte ich mich um die Umsetzung kümmern. Ich hatte mir vorgestellt, dass eine Spielrunde drei Minuten dauern sollte, und dass zwischen den Spielen eine 30 Sekunden lange Pause sein sollte. In diesen 30 Sekunden muss demnach ein neues Spiel berechnet, die Ranglisten in der Datenbank aktualisiert, und das Ergebnis des letzten Spieles angezeigt werden. Das bedeutet, dass mir für die Berechnung eines neuen Spieles weniger als 30 Sekunden blieben. Kein Problem, dachte ich mir. Ich bin ja nicht der erste, der das versucht. Und Anderen ist das schließlich schon gelungen.

Spielfeld auswürfeln


Jedes Spiel besteht aus einem Quadrat mit 16 zufälligen Buchstaben. Zufällig? Nein, nicht ganz. Es sollen ja schließlich einige Worte auffindbar sein. Also habe ich mir von Wikipedia eine Tabelle mit Häufigkeitsverteilungen besorgt, die ich bei der Ziehung der Buchstaben berücksichtige.

RangBuchstabeHäufigkeit
1E17,40 %
2N9,78 %
3I7,55 %
4S7,27 %
5R7,00 %
6A6,51 %
7T6,15 %
8D5,08 %
9H4,76 %
RangBuchstabeHäufigkeit
10U4,35 %
11L3,44 %
12C3,06 %
13G3,01 %
14M2,53 %
15O2,51 %
16B1,89 %
17W1,89 %
18F1,66 %
RangBuchstabeHäufigkeit
19K1,21 %
20Z1,13 %
21P0,79 %
22V0,67 %
23J0,27 %
24Y0,04 %
25X0,03 %
26Q0,02 %


Außerdem achte ich darauf, dass in einem Spiel mindestens zwei, aber nie mehr als sechs Vokale vorkommen. Damit ist die Wahrscheinlichkeit sehr hoch, dass jedes Spiel einige, aber nicht zu viele Lösungswörter hat.

Spielfeld lösen


Einfach alle Kombinationen durchzuprobieren, und im Wörterbuch nachzuschlagen, war erwartungsgemäß viel zu langsam. Aber dieser brutale Ansatz ist auch gar nicht notwendig. Denn in der Regel steht schon früh fest, dass es keine Wörter gibt, die mit den Buchstaben der zu untersuchenden Kette beginnen. Am Beispiel des Logos von Sechzehn beginnt die Suche mit R, und kann bei RP schon abbrechen. Es gibt keine Wörter die damit anfangen. Als nächstes muss die Kombination RS untersucht werden, für die auch keine Wörter existieren. Also weiter mit RE, RES und RESZ - hoppla schon wieder eine Sackgasse. Auf diese Weise sind letztendlich nur ein verschwindend geringer Bruchteil aller theoretisch möglichen Buchstabenkombinationen tatsächlich zu untersuchen. Die Lösung eines Spielfelds liegt dadurch in der Regel deutlich unter fünf Sekunden.

Der erste Stolperstein auf dem Weg zu einem spielbaren Sechzehn ist ausgeräumt. Jetzt konnte ich also daran gehen, einen Einzelspielermodus zu programmieren, in dem alles Notwendige für das Eingeben und Prüfen von Wörtern vorhanden ist.

Dienstag, 25. März 2014

Vorbereitung - Look & Feel

Der Entschluss ein online Boggle zu programmieren war gefasst. Jetzt ging es darum, vor der ersten Zeile Code ein paar Dinge zu klären:



Look & Feel


Sechzehn sollte frisch und modern aussehen. Daher fiel meine Wahl auf das Bootstrap Framework. Bootstrap wurde ursprünglich bei Twitter entwickelt, und ist inzwischen eines der beliebtesten Projekte auf GitHub. Mit Bootstrap erstellte Webdesigns empfinde ich als optisch sehr ansprechend. Sie haben eine klare Linie, und sie wirken modern.

Das dreispaltige Layout von Sechzehn habe ich einfach von meinen Lieblings-Boggle-Varianten im Netz übernommen (WordsPlay und Wortopia). Wie man sehen kann, ist das Layout von Sechzehn eine Mischung dieser beiden Boggle-Varianten.

Ein erster Mockup war schnell fertig, und seither haben sich lediglich vorsichtige Änderungen im Detail ergeben. Im Grunde ginge es bei diesen Eingriffen ins Layout immer darum, die Sichtbarkeit von Sechzehn für Suchmaschinen zu verbessern. Ach ja. Suchmaschinenoptimierung und Werbung. Auch zwei Themen, über die ich berichten will. Aber nicht jetzt.




Vorbereitung - Features

Der Entschluss ein online Boggle zu programmieren war gefasst. Jetzt ging es darum, vor der ersten Zeile Code ein paar Dinge zu klären:


Features


Frei nach dem Motto "weniger ist mehr", habe ich eine Liste der wirklich wichtigen Features von Sechzehn erstellt. Auf alles, was nicht unbedingt für das Spiel notwendig ist, sollte verzichtet werden. Damit blieben die folgenden Features übrig:

Ob ein Mehrspielermodus mit Ruby on Rails überhaupt realisiert werden konnte, war mir noch nicht klar. Auch die Frage, ob neue Spielfelder mit Lösung innerhalb vertretbarer Zeit generiert werden konnten, musste ich erst noch klären. Dass Touchbedienung im Browser unterstützt wird hatte ich zwar mal gehört, ob dem wirklich so war, wusste ich noch nicht. Und schließlich galt es noch zu klären, ob Ranglisten und kein Zwang zur Registrierung miteinander vereinbar sind. Zumindest dafür hatte ich sofort eine pragmatische Lösung. Spielresultate von nicht registrierten Spieler würden einfach nicht in den Ranglisten auftauchen.