Wednesday, November 23, 2005

Während Mario's letzter Session gestern auf der Launch Conference 2005 in Wien gab's die erste Live-Preisverleihung bei einem .NET Golfturnier. Auf die ersten drei Plätze gegolft hatten sich Thomas Gatterweh, Franz Polzer und Claudia Krolopp. Bevor Mario zur Preisverleihung schritt (und das dekorative Snowboard damit die Bühne verließ), habe ich der versammelten Entwicklergemeinde kurz und prägnant das Golfkonzept vorgestellt.

Zumindest der Part, daß man keinerlei Coding Style Guidelines einhalten muß, dürfte einigen Programmierern gefallen haben.

Natürlich durfte das Leaderboard nicht fehlen:

Danach ging's zur Preisverleihung, beginnend mit Claudia, die den MP3 Player bekam:

Dann betrat Franz die Bühne, um das Snowboard abzuholen (man bemerke den Code auf der Slide, unkommentiert - die Post Mortems sind hier zu finden):

Thomas erhielt einen MDA sowie (demnächst) ein Visual Studio Pro (das Foto wurde leider nichts, sorry).

Das nächste Turnier kommt bestimmt, und es wird mit .NET 2.0 ausgetragen werden!

Wednesday, November 23, 2005 2:47:12 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
 Monday, November 21, 2005

Das Solitaire Encryption Golfturnier war eine Challenge unter den Ägiden von Microsoft Österreich, unser Codefairway diente als bewährter Austragungsort für diesen MSDN Contest. Die Regeln und das finale Leaderboard sind ebendort nachzulesen - hier in diesem Blogpost sind die Post Mortems der Winning Entries zusammengetragen.

Die Post Mortems sind wie immer von den Golfern selbst verfasst, und werden hier ungekürzt und ungeschminkt nachgedruckt. Den optimierten Code kann man als angemeldeter Golfer im Leaderboard nachlesen (auch wenn's ohne diese Erklärungen nicht viel helfen wird <g />).

Platz 3, Claudia Krolopp

 Spät, aber doch ...

Im Gegensatz zu Franz bin ich absolut nicht der Meinung, dass das was hier verbrochen wurde selbsterklärend sein soll. Ich hab schon Probleme meine eigene Code-Zeile zu durchblicken.

Aber ich versuchs mal:

Bei mir muss als Kartenstapel kein string sondern ein int array herhalten.

Der Stapel wird mit 1 beginnend initialisiert, die beiden Joker erhalten beide den Wert 53 (an irgendeiner Stelle im Algorithmus muss für beide der gleiche Wert verwendet werden).

Heisst allerdings auch, dass die Position der Joker immer bekannt sein muss, deshalb werden bei jeder Veränderung im Stapel die Indices beider Joker (x und y) mitgezogen.

Sämtliche Verschiebungen werden in einer einzigen Funktion M( int j, int k ) durchgeführt, wobei immer die ersten j Karten k mal um 1 nach hinten geschoben werden. k wird returniert und wiederverwertet.

Sieht dann z.B. beim Verschieben einer Karte um 1 nach hinten so aus:

x=4;
     1234x5678y90
M(x,x);
     x12345678y90
M(1,k%53+1);
     12345x678y90

Mit k%53+1 funktioniert auch das Verschieben der letzten Karte reibungslos.

using S=System.String;
public class Tee
{
    // In "r" landet der verschlüsselte string, in "s" der key und 
    // "o" wird mit dem Alphabet in Grossbuchstaben initialisiert.

    S r,s,o;

    // Jede Menge Hilfsvariablen und das Kartendeck "a".
    int i,t,v,x,y,l,p,q;
    
int[]a=new int[54];

    // Hier werden j Karten k mal verschoben
    // in "x" und "y" werden die Positionen der Joker aktualisiert

    int M(int j,int k)
    {

        for(;j-->0;y+=y<1?k:y>k?0:-1,x+=x<1?k:x>k?0:-1)
            for(t=a[i=0];i<k;a[i]=t)
                a[i++]=a[i];

        return ++v>5?k:v%2>0?M(1,k%53+1):M(y,y);
    }

    // GenerateKeyStream generiert nicht nur den KeyStream sondern
    // auch gleich die verschlüsselte Nachricht

   

public S GenerateKeyStream(S P,S m)
    {
        // Bei der Initialisierung wird gleichzeitig "P" mit Ziffern angefüllt.
        // Damit ist es möglich beide Teile des Algorithmus, also über den ganzen
        // string "P" und bis die benötigte KeyStream-Länge erreicht ist, in 
       
// einer einzigen Schleife abzuarbeiten.

        for(y=l=p=0;y<53;P+=a[x=y]=a[++y]=y)
             o+=(char)(y%26+65);

        // Und hier wird nun endlich der ganze Algorithmus aufgerufen.
        // Der momentane Buchstabe in "P" wird auf Kartendeckwert runter-
        // gerechnet und in "q" gespeichert. 
        // War es ein Grossbuchstabe, dann ist q > 0 und die strings werden
        // nicht verändert.
        // War es eine der angehängten Ziffern, dann sind wird durch "P"
        // durch und können anfangen die strings zu basteln.
        // Wenn die Nachricht vieeeel länger als das passwort ist, kann es
        // allerdings sein, dass die angehängten Ziffern mengenmässig nicht
        // reichen (war bei mir anfangs der Fall) - dann kann "P" auch direkt
        // im if verlängert werden - kostet allerdings noch ein Byte extra
        // und wenns dem Tester so genügt ...

        

for(r=s="";l<m.Length;)
             if(M(q=P[p++]-64,M(a[M(M(x<M(x,x)?x:y,x>y?x:y)+1,53)],52))>(i=a[a[v=0]]-1)&q<1)
            
{
                 
s+=o[i];
                 r+=o[m[l++]-64+i%26];
             }

        // Ab jetzt isses wirklich selbsterklärend.

        return s;
     }

     public S EncryptData(S m,S k)
     {
         return r;
     }
}

Platz 2, Franz Polzer

Eigentlich ist der Code sowieso selbsterklaerend :)

c  Kartendeck
d  Keystream
e  Encrypted Message
f  lookup Table um (char) typecast und Offset von 'A' zu sparen
i  Startposition des zu verschiebenden Bereichs
z  Zielposition des zu verschiebenden Bereichs

using S=System.String;
public class Tee
{
        S c,d,e,f;
        int i,z;
        char j,u,l='A',a,b='5';
        public S GenerateKeyStream(S p,S m)
        {
                // Initialisieren des Kartendecks und der Lookup-Table
                for(;a<54;c+=++a)f+=l++;
                // Solange bis die Message encrypted ist
                for(;u<m.Length;)
                {
                        // Move der beiden Joker
                        for(l=b;l<=a;M(1))
                                z=((i=c.IndexOf(l))+l++)%b+1;
                        // Triple Cut
                        S[]k=c.Split(b,a);
                        c=k[2]+c.Trim((k[0]+k[2]).ToCharArray())+k[i=0];
                        // Countcut mit letztem Zeichen
                        z=52;
                        M(c[b]);
                        try
                        {
                                // Countcut mit Passphrase solange noch
                                // ein Zeichen da ist.
                                // Sonst -> Exception
                                M(p[j++]%64);
                        }
                        catch
                        {
                                // Auslesen des Zeichens fuer Keystream
                                // und erzeugen der encrypted Message
                                if(b>(i=c[c[0]>b?b:c[0]]))
                                        e+=f[(m[u]+(d+=f[--i%26])[u++]+1)%26];
                        }
                }
                // Keystream zurueckgeben
                return d;
        }
        public S EncryptData(S m,S p)
        {
                // Einfach die vorher berechnete Message zurueckgeben
                return e;
        }
        void M(int y)
        {
                // verschieben von y Zeichen von i nach z
                c=c.Remove(i,y).Insert(z<i?z:z-y+1,c.Substring(i,y));
        }
}

So, das war's eigentlich schon!

Platz 1, Thomas Gatterweh

/*
Die Idee.
Alle Veränderungen im Kartenstapel können durch eine Funktion ausgedrückt werden: Das Verschieben einer oder mehrerer Karten an eine andere Position im Stapel. Es müssen nur mehr die jeweiligen Start-, End- und Zielpositionen berechnet werden.
J
 
Die Joker.
Um ein Zeichen (";") zu sparen, wird die erste Jokerverschiebung nicht als erstes in der Schleife gemacht, sondern als letztes (im "for"). Das ist insofern möglich, da diese erste Jokerverschiebung im allerersten Durchlauf lediglich die beiden Joker vertauscht. (Der Stapel ist ja frisch aufgebaut.) Damit kann ich diese Vertauschung weglassen, und muss jetzt nur die Bedeutung von Joker #1 und #2 vertauschen. Deshalb hat Joker #1 den Wert 54 ("6") und Joker #2 den Wert 53 ("5").
 
Das Green.
Es lässt sich folgendes herausfinden:
a) Die Klasse "Tee" wird jeweils nur zum Verschlüsseln einer einzigen Nachricht benutzt. ==> Ich verwende soweit wie möglich die Defaultinitialisierung von Klassenelementen, z.B. int wird als 0 initialisiert.
b) "GenerateKeyStream" und "EncryptData" wird immer 'korrekt' paarweise benutzt. ==> Die Nachricht kann schon in "GenerateKeyStream" verschlüsselt werden. Die Parameter von "EncryptData" setzte ich einfach als korrekt voraus.
*/
using S = System.String;
public class Tee
{
        
/*
         "a" enthält in den ersten 54 Zeichen den Kartenstapel; der Rest bis Zeichen 90="Z" wird zum Wandeln einer Zahl in ein Zeichen verwendet.
         "k" ist der KeyStream.
         "e" ist die verschlüsselte Nachricht.
         */
         S a, k, e;
        
/*
         "i" ist die Position des Jokers #1, "j" die des Jokers #2. "j" wird gleich am Anfang gebraucht und muss initialisiert werden.
         */
         int h, i, j = 52, l, n;
        
/*
         "x" enthält a) das Zeichen des Jokers #2 (siehe oben) und auch b) 53, d.h., 1-Anzahl der Karten.
         "y" enthält in der Hauptschleife a) das Zeichen des Jokers #1 und auch b) 54, d.h., die Anzahl der Karten.
         Zuerst wird "y" allerdings zum Initialisieren von "a" verwendet. Der Defaultwert von 0 passt dafür hervorragend.
         */
         char x = '5', y;
        
/*
         "EncryptData" liefert nur mehr die bereits generierte verschlüsselt Nachricht zurück.          */
         public S EncryptData( S m, S k )
         {
                  
return e;
         }
        
/*
         "C" verschiebt einen Kartenstapel, gegeben durch die Position "s" der ersten Karte und "e" der letzten Karte (exklusiv), an die Position "z".
         Ist "s" größer oder gleich "e", wird nichts verschoben.
         "i" und "j" wird mit der neuen Position des 1. und 2. Jokers aktualisiert.
         */
         void C( int s, int e, int z )
         {
                   a = a.Remove( s, e -= s < e ? s : e ).Insert( z, a.Substring( s, e ));
                   i = a.IndexOf( y );
                   j = a.IndexOf( x );
         }
        
/*
         "GenerateKeyStream" verschlüsselt auch noch gleich die Nachricht und hebt sich das Ergebnis für "EncryptData" auf.
         */
         public S GenerateKeyStream( S p, S m )
         {
                  
// Ein Kartenstapel muss her...
                   for( ; y < 90; )
                            a += ++y;
                  
// Jetzt noch schnell "y" initialisiert, und dann kann es losgehen bis alle Zeichen da sind...
                   for( y = '6'; n < m.Length; C( i, 1 + i, i % x + 1 ))
                   {
                           
// Jokerverschiebung (am Ende des "for" für Joker #1, bzw hier für Joker #2)
                            // Von alter Jokerposition eine Karte an die neue Position verschieben.
                            C( j, ++j, j % x + 1 );
                           
// TripleCut in zwei Schritten...
                            // Wo ist der vordere Joker?
                            h = i < j ? i : j;
                           
// 1. Schritt: Die Karten von der Karte nach dem hinteren Joker (wenn "h" der vordere ist, dann ist "i+j-h" der hintere!) bis zum Ende an die Position vor dem vorderen Joker verschieben.
                            C( i + j - h + 1, y, h );
                           
// 2. Schritt: Die Karten vom Anfang bis zum (ursprünglichen) vorderen Joker ans Ende verschieben.
                            C( 0, h, y - h );
                           
// CountCut gemäßder letzten Karte
                            // Invers zur Beschreibung: Ich verschiebe nicht die N ersten Karten unmittelbar vor die letzte Karte, sondern verschiebe die Karten von der N-ten bis zur vorletzten an den Anfang.
                            C( a[ x ], x, 0 );
                           
try
                            {
                                     
// CountCut nach dem nächsten Zeichen in der PassPhrase. Gibt's dort keines (mehr), geht's per Ausnahme zur Ausgabe...
                                      C( p[ l++ ] - 64, x, 0 );
                            }
                           
catch
                            {
                                     
// Ausgabekarte holen, und wenn kein Joker...
                                      h = a[ a[ 0 ] < x ? a[ 0 ] : x ];
                                     
if( h < x )
                                      {
                                              
// ...dann Message verschlüsseln...
                                               e += a[( h + 13 + m[ n++ ]) % 26 + 64 ];
                                              
// ...und KeyStream erzeugen.
                                               k += a[ --h % 26 + 64 ];
                                              
// Beide Male wird der unverändert bleibende Teil des Kartenstapels (alles außer den ersten 54 Zeichen) zum Umwandeln des Kartenwertes in ein Zeichen verwendet.
                                      }
                            }
                   }
                  
return k;
         }
}
 

Monday, November 21, 2005 3:38:27 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
 Friday, September 30, 2005
Seit 23 Uhr läuft das aktuelle Golfturnier, das diesmal (a) anspruchsvoll ist, (b) ensprechend Zeit läßt, (c) schöne Preise für die Gewinner bietet. Bernd und Ich freuen uns, das zusammen mit Mario Szpuszta von MS Österreich auf die Füße gestellt zu haben. Viel Spaß!
Friday, September 30, 2005 10:30:36 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
 Wednesday, August 17, 2005

So lautet die Aufgabe des aktuellen Golfturniers. Mal sehen, ob die Golfer das auch so sehen. Jedenfalls haben sie von jetzt an gerechnet eine Woche Zeit, ihre Golftricks auszupacken.

Wednesday, August 17, 2005 1:58:27 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
 Sunday, August 14, 2005

Am Mittwoch um 15 Uhr startet ein neues Golfturnier! Ihr könnt schon mal die Golfschläger polieren und Euch auf ein rasantes, einwöchiges Turnier einstellen.

Sunday, August 14, 2005 2:48:02 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
 Monday, January 03, 2005

Nach langer Wartezeit ist es so weit - das allseits beliebte ASP Golf wird nun seine Fortsetzung auf der .NET Plattform finden, und zwar auf dem CodeFairway. Die Web Applikation stammt von Alex Zeitler (ein dickes Dankeschön an dieser Stelle, er hat da so einiges an Zeit investiert), den Tester darf sich der BLfH anrechnen (zugegebenermaßen der weitaus leichtere Teil). Im Moment spielen wir ein Testturnier, um dem Grün den letzten Schliff zu geben - sowohl von der User- als auch der Adminperspektive aus.

Monday, January 03, 2005 5:03:08 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
 Tuesday, April 27, 2004

Im Attachment zu diesem Blogeintrag zeige ich wie ich mir ein .NET Golfturnier vorstelle, der eigentliche Tester und der Abschlag des Golfers sind hierbei für das einfachere Verständnis miteinander gemischt.


In der #develop Combine sind 3 Projekte enthalten:

* Tees: da drinnen sind die Interfaces definiert, dagegen linkt jede Aufgabe. Pro Aufgabe gibt es ein Interface das von ITee ableitet (für spätere Erweiterungen im Tester gedacht). Das aktuelle Turnier ist durch ITeeGroupTransform abgebildet.

* GroupTransformTeeOffSample: hier habe ich Peter's Schlag in den Bunker implementiert, in der Datei TeeOff.cs. Die Klasse *muß* immer Tee heißen sowie das Turnierinterface implementieren. Der Rest ist Sache des Golfers...

* GroupTransformTester: das ist unsere (Referee) Applikation. Im echten Leben wird das alles von der Kommandozeile aus gemacht: TeeOff.cs [oder wie auch immer die Einreichung des Golfers dann heißt], Interfaces.cs und Tester.cs werden mittels csc zu einer Assembly kompiliert, und dann vom Kommandozeilen-NUnit getestet. Der Einfachheit halber verwende ich heute aber das NUnitPad das im aktuellen #develop drinnen ist (http://svn.sharpwt.net/dev/). Damit wird es perfekt automatisierbar.

Das ist einmal die Basis - Reflection und dynamisches Laden einer Assembly habe ich mir mit dieser Lösung erspart. Kommentare?

DotNetGolf.zip (18.2 KB)
Tuesday, April 27, 2004 2:40:03 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]