Bernhard Häussner
Tags: Artikel mit dem Tag «App» durchstöbern

MacMahonMosaik Online Game

09.07.2009, 18:05
Mac Mohan Mosaik

Mac Mohan Mosaik

Da ich beim Känguru-Wettbewerb 2009 mitgemacht habe, habe ich auch das MacMahonMosaik in die Hände bekommen. Es ist ein kleines Rätsel ähnlich wie Sudoku. Weil es interessant zu Modellieren ist, habe ich das MacMahonMosaik als Online-Spiel erstellt. Hier ein paar Details zu Implementierung:

Modell

Jedes Quadrat im Spiel hat 4 Kanten, die in 3 verschiedenen Farben markiert sein können. Daher lässt sich jede Anordnung als 4-Tupel einer 3-Menge auffassen. Diese 81 Tupel wiederum können den natürlichen Zahlen von 0-80 zugeordnet werden. Somit habe ich als Objekte zunächst die 24 Quadrate (die anderen fallen weg, da sie durch Drehung erreicht werden können), die jeweils eine Zahl speichern. Sie müssen sich nun z.B. drehen können. Dazu wird die Zahl in das Tupel umgerechnet und die Einträge des Tupels um eine Stelle verschoben, wobei der letzte Eintrag der erste wird. Um zu Überprüfen, ob zwei Quadrate aneinander passen, dreht man eines der beiden zweimal und schaut dann einfach ob in der gewünschten Richtung die selben Farben stehen. Dadurch sieht die Prüffunktion im Javascript sehr kurz aus:

p.checkMatch=function(other,pos){
  var mycodes=this.getColorCodes(); // Tupel aus Zahl
  var o=other.clone(); // Neues Quadrat mit selber Zahl
  var othercodes=o.rotate().rotate().getColorCodes(); // anderes Q. 2x drehen
  return (mycodes.charAt(pos)==othercodes.charAt(pos)); //prüfen
}

Zusätzlich haben die Quadrate noch ein paar Darstellungsrelevante optionale Eigenschaften und Methoden. Ist ihnen ein <Canvas>-Element im HTML-Baum delegiert, können sie ihm die passenden Event-Handler für das interaktive Drehen und Bewegen zuweisen und eine graphische Repräsentation ihrer selbst zeichnen. Und sie speichern einige Daten für drag & drop.

Doch beim Ziehen und Ablegen kommt das zweite Objekt ins Spiel: Das Feld in dem die Quadrate abgelegt werden können. Wann immer man ein Quadrat bewegt, frag dieses Quadrat beim Gitter nach, ob es sich einrasten kann. Das Gitter gäbe dann die Pixel-Koordinaten des Einrastpunkts auf dem Bildschirm und die Koordinaten innerhalb des Gitters zurück. Wird das Quadrat dann fallen gelassen, registriert es sich im Gitter.

Das Gitter hat dazu ein zweidimensionales Feld hinterlegt, in dem es Pointer zu den abgelegten Quadraten speichern kann. Wenn jetzt ein Quadrat im Raster abgelegt wird und sich registriert hat, weist es das Raster an, sich zu revalidieren - Das Gitter ruft für jedes Quadrat und je seine vier Nachbarn die Prüffunktion auf. (Da das „Passen“ symmetrisch ist, ließe sich die Komplexität des Algorithmus vielleicht noch optimieren, doch das hätte wieder mehr Code zur Folge und bei 24 Einheiten...) Da das Gitter nur Zeiger zu den Quadraten speichert, ist bei einer Drehung eines Quadrats keine weitere Registrierung nötig. Falls also ein Quadrat angeklickt wird, rotiert es sich, aktualisiert die eigene Darstellung und gibt den Revalidierungsbefehl an das Raster.

Für die Darstellung hat das Gitter auch eine recht einfache Methode, die den Feldhintergrund rötlich färbt, sollte ein Fehler vorliegen und eine Gratulation meldet, sollten alle Quadrate an einem passenden Ort sein, also das Spiel gewonnen.

Ablaufdiagramm

Hier mal ein kleiner Flowchart. Man beginne das Lesen bei den Event-Handlern: (erstellt mit U+2500-U+257F: Box Drawing)

Quadrat
├ Zahl ◁──────┐ {Umrechnung}
├ (Tupel) ◁───┘
├ Drehen() ◀────────┐◁──┐─┐▷─────┐
├ Prüfen(Quadrat) ──◆───┊─┊──────┊──┐
├ [Darstellung]     │   │ │      │  │
│  ├ Visualisieren◁─┊───┊─┘      │  │
│  └ [Handler]      │   │        │  └──┐
│     ├ Klick ──────┊───┘        │     │
│     ├ Packen  ────┊────────────┊──┐  │
│     ├ Bewegen ◀───┊───┐        │  │  │
│     └ Ablegen ────┊─────────┬▷─┤  │  │
└ Kopieren() ►──────┘   │     │  │  │  ▼ bool
                     [XY,XY]  │  │  │  │
Gitter                  │     │  │  │  │
├ Feld[X,Y]             │     │  │  │  │
├ KoordinatenBei(XY) ───┘     │  │  │  │
├ Registrieren(Quadrat)  ◀─XY─┘  │  │  │
│ └ Un-Registrieren() ◀─────XY───┊──┘  │
├ Alle Prüfen()  ►────────┐─▷────│─────┘
└ Darstellung erneuern() ─┘  ◁───┘
  └ Färben(), Gratulation()

Wie das Gitter überprüft, ob auch am Rand rote Kanten liegen? Statt weiteren Code für den Rand zu basteln, wird das Gitter mit voll-roten Quadraten ohne graphische Repräsentation außerhalb das Gitters vorbelegt. Das hat den kleinen Nebeneffekt, das auch out-of-bounds-Fehler im Prüfalgorithmus vermieden werden, da ja z.B. bei negativen Gitterkoordinaten -1 stets ein solches „virtuelles“ Quadrat liegt.

Wie man also sieht, kann man an diesem Spiel schon einige lustige Code-Spar-Methoden benutzen. Eigentlich sparen sie nicht nur Code, sondern auch Nachdenken, wenn man sie „sieht“.

Javascript Umsetzung

JS-Closures habe ich in letzter Zeit immer mehr zu schätzen gelernt. (Man muss in PHP übrigens auch nicht mehr lange darauf verzichten) Sie lassen den Programmierer Funktionen, also mehr oder weniger Code, wie ein String oder eine Zahl an andere Funktionen übergeben oder in Variablen spichern, sodass mit anonymen Funktionsobjekten als Closures in JS eigene Kontrollstrukturen definiert werden können, wie diese zweifache for-Schleife, um über Koordinaten bzw. Zweidimensionales zu loopen:

function loopXY(w,h,cb) {
  for (var x=0;x<w;x++) {
    for (var y=0;y<h;y++) {
      cb(x,y);
    }
  }
}
var m=[];
loopXY(5,7,function(x,y){
  m.push("("+x+","+y+")");
});
alert(m);

Wie man sieht stehen in Javascript in den Closures alle äußeren Variablen zur Verfügung. Das wiederholte verwenden des Namens einer äußeren Variable führt trozdem noch dazu, dass in der Closure diese lokal verwendet wird und außen der alte Wert erhalten bleibt. Ein bischen gewöhnungsbedürftig ist die Verwendung von this in JS. Im oben gezeigten Code würde z.B. in der Schleife this auf window zeigen. Das lässt sich mit der Function.call oder der Function.apply-Funktion kompensieren, wie in diesen Code-Schnippseln für Event-Handler.

Für die Erstellung von Objekten (außer reinen Datenspeichern, die mit {} einfach erstellt werden können) verwende ich folgende Grundstruktur:

function Square(id) { // constructor
	this.id=id; // Eigenschaften initialisieren
}
(function(){
  var p=Square.prototype; // shortcut zum Prototype
  p.setId=function(id) { // einfacher Setter
    this.id=id;
    return this; // macht Setter chainable
  };
  var privat; // kann nur von den Objektmethoden gesehen werden
  function privatauch() {} // dito
})();
var s=new Square (3);

Allerdings bin ich mir nicht sicher, ob das wirklich besser ist, als alles in Konstruktoren zu packen.

Der Code des Onlinegames ist vielleicht nicht ganz so interessant zu lesen, wie es war ihn zu erstellen, aber ich denke, hinein schauen lohnt sich. Ich bin natürlich immer interessiert an weiteren Javascript-Techniken und Tipps zur Code-Gestaltung.

Kommentare: keine

Greasemonkey Quick Search

21.04.2009, 20:10
Greasemonkey Quick Search

Greasemonkey Quick Search

Man muss ja nicht immer gleich eine Firefox-Erweiterung basteln, wenn man Firefox nur ein bisschen erweitern will. Wesentlich einfacher und schneller geht das (natürlich nur bei bestimmten Dingen) mit Bookmarklets, wie meinem Twitter Bookmarklet. Oder mit Greasemonkey, einer Firefox-Erweierung, die bestimmte Javascripts auf bestimmten Seiten ausführen kann. Ich habe mir ein kleines „Userscript“ gebastelt, dass, wann immer ich Text auf einer Webseite markiere, eine Reihe von Suchoptionen anzeigt.

Das Script registriert einen mouseup-Event-Handler und wenn Text auf der Webseite selektiert ist, öffnet dieser ein kleines Menü mit dem man dann den Text z.B. Googeln kann. Es unterstützt auch noch Google Maps, Wikipedia, und das Leo-Wörterbuch. (Ich hasse es nämlich ganze Texte mit Google zu übersetzen, wenn ich nur ein Wort nicht kenne, weil sich Englisch doch besser liest als Googles Deutsch.)

Um das Script zu benutzen muss man die Greasemonkey-Erweiterung installiert haben. Dann kann man das Script hier installieren:

Wer sich etwas mit HTML auskennt kann auch eigene Funktionen leicht nachrüsten.

Es gibt übrigens ein Verzeichnis vieler Greasemonkey-Scripte auf http://userscripts.org/

Changelog

  • 23.04.2009 - Updated to support twitter search too.
  • 09.07.2009 - Updates: tweet selected quotes and use selected text as URL.

If you're really missing something else and you think others do so too, let me know in the comments.

Kommentare: keine

ShortURL Auto-Discovery Twitter Bookmarklet

07.04.2009, 17:44
Tweet-this-Bookmarklet

Tweet-this-Bookmarklet

Recently I've created a boomarklet to post links quickly to twitter using URL-shortening. The main feature was that you don't have to login on 3rd party web sites because it takes you to twitter. But now there's some more improvement: The new bookmarklet looks for a tiny url on the website itself in a <link rel="short_url"-Tag> (thanks to Snaplog).

To install just drag this link in your bookmark toolbar and you're done:

tweet this

Since there are not too many pages that implement the short_url tag, it falls back to is.gd shortening if it couldn't find one. To test it navigate to a page that offers a short_url for example: http://robert.snaplog.com/:E39/brooklyn_not_ark

Edit 2009-10-22: New Version

The new major version Twitter Bookmarklet III is available.

New in Version 0.9.3.5:

Since the short_url could lead to confusion with URL/URI and has the underscore I've updated the bookmarklet again to support rel="shortlink" too, which seems like a better term. There was of course some discussion.

New in Version 0.9.2:

The bookmarklet has been updated again to allow the short_url keyword to be one of a space separated list. This means it works now on arstechnica.com.

New in Version 0.9.1:

I had to update the bookmaklet to support relative URLs as used by http://www.geograph.org.uk/photo/19. In Javascript element.href returns the full, absolute url like http://e.com/absolute etc. while l.attributes[x].nodeValue may return something like /relative.

Kommentare: 2 Einträge

No login tweet-this Twitter Bookmarklet

31.03.2009, 16:43
Tweet-this-Bookmarklet

Tweet-this-Bookmarklet

Tipp: There's a newer version of the bookmarklet available.

Today I added a "follow me at twitter" button to my blog. And then I considered to include a "tweet this" button somewhere on all pages. But I realized that I would maybe have to add delicious, digg etc. too. But nobody really uses these buttons because they have delicious toolbar, bookmarklet or something similar that works on all web sites. I came to the result that I need a twitter bookmarklet. But although there are some on the net, I couldn't fine one, where you don't have to give away your twitter account data. So I created one:

tweet this

Just drag the link to your toolbar and klick the button whenever you wan to tweet a page. It will open twitter.com on your /home-page with a is.gd-shortened link to the page and the title of the page pre-filled in the textarea. If you are not logged in, Twitter will ask you for your account data, so you're never giving away your password to 3rd party apps.

Let me know if something doesn't work in the comments.

You could of course include this link in any web page as quick and dirty tweet this button, to spare you trouble with server-side URL shortening. But keep in mind it won't work without javascript.

Deutsch:

Heute habe ich einen „follow me at twitter“-Button auf meinen Blog gesetzt. Dann habe ich mir überlegt einen „tweet this“-Button irgendwo in alle Seiten einzubringen. Aber ich stellte fest, dass ich vielleicht delicious, digg etc. auch hinzufügen müsste. Aber niemand benutzt diese Icons, da jeder die Delicious-Toolbar, ein Bookmarklet oder ähnliches hat, das auf allen Webseiten funktioniert. Ich kam zu dem Schluss, dass ich ein Twitter-Bookmarklet brauche. Obwohl es einige im Internet gibt, konnte ich keines finden, wo man seine Twitter-account-Daten nicht hergeben muss. Also habe ich eines erstellt:

tweet this

Einfach den Link in die Toolbar ziehen und dann den Butten klicken, wenn Sie eine Webseite twittern wollen. Er wird twitter.com auf ihrer „home“-Seite öffnen mit einem is.gd-gekürztem Link zu der Seite und dem Titel der Seite vor ausgefüllt in der Textarea. Wenn Sie nicht eingeloggt sind, wird Sie Twitter nach ihrem Passwort fragen, also müssen Sie niemals Ihr Passwort an Anwendungen von Dritten weitergeben.

Lassen Sie mich via Kommentarfunktion wissen, falls etwas nicht funktioniert.

Man könnte natürlich diesen Link auch in jede Webseite einfügen als „quick and dirty“ tweet this-Button, um sich den Aufwand von Server seitigem URL-Kürzen zu sparen. Aber der Button kann natürlich nicht ohne Javascript funktionieren.

Kommentare: 4 Einträge

YaSvenT - eine PHP-GTK-Anwendung

10.01.2009, 08:46

Zugegeben - PHP ist nicht unbedingt die beste Programmiersprache wenn es um Desktop-Anwendungen geht. Doch um einen Einstieg in GUI-Programmierung zu finden, wollte ich erstmal mit einer mir gut bekannten Programmiersprache anfangen. Und mit den Objekten von PHP5 ist der Unterschied zu z.B. Java auch nicht mehr allzu groß, wenn auch deutlich spürbar. Also habe ich mich daran gemacht ein GUI-Basiertes Server-Kontrollzentrum zu basteln.

Einmal konfiguriert kann es Backups von MySQL-Datenbanken und den Dateien machen, das Error-Log anzeigen, das Access-Log in eine SQlite-Datenbank umwandeln und daraus einen HTML-Bericht erstellen, und Programme wie SSH-Konsole, Webbrowser, MySQL-Tunnel oder SFTP-Browser auf einen Klick vorkonfiguriert öffnen. Das ist recht praktisch, wenn man nicht den Ganzen Tag URLs und Befehlsfolgen tippen will. Da ich für das Meist sowieso schon Shell-Skripte hatte, lag das Ziel hauptsächlich darin, ein nettes GUI zu basteln.

Mit PHP Desktop-Anwendungen zu basteln hat den Nachteil, dass unter gängigen Linux-Distributionen zwar alles funktionieren dürfte, allerdings unter Windows PHP und GTK benötigt wird. Außerdem ist die Dokumentation von PHP-GTK noch nicht auf der vom übrigen PHP gewohnten Qualität. Einige Widgets sind nicht oder unvollständig gelistet, Beispiele sind teilweise rar und Englisch-Kenntnisse wären ratsam. Ich denke die nächste GUI-Anwendung werde ich in Java versuchen und dann vergleichen, aber mir kam es nicht so vor, als würde ich in einer Perl-Skriptesammlung für die Personal Homepage coden, und ich denke PHP ist langsam erwachsen.

Kommentare: keine
 
Χρόνογραφ
© 2008-2017 by Bernhard Häussner - Impressum - Login
Kurz-Link zur Homepage: http://1.co.de/