** Brainfuck Interpreter Contest ** [abgeschlossen]



  • µ schrieb:

    Wie wäre es mit sehr einfachen Bots die in irgendeiner Form gegeneinander antreten?

    Daran hätte ich auch Interesse.





  • Sowas wie Core-War, ja.

    Das würde Einarbeitung erfordern (ich kenne mich auch noch nicht damit aus), oder wir arbeiten ein eigenes kleines Bot-Framework aus. Es könnte ja sehr einfach anfangen und im Laufe der Zeit erweitert werden.



  • Optimalerweise kann so ein Contest ohne Ende sein. Es gibt halt eine laufend aktualisierte Rangliste. Und

    Core-War ist Core-War. Man proggert da in Redcode. Nicht in C#.

    Gut ist Colobot bzw Ceebot. Extrem gut. Aber das Framework zu basteln, würde wohl den Rahmen sprengen.

    Mein liebstes Game wäre wohl http://en.wikipedia.org/wiki/Classic_Empire_(video_game) , da hat mir immer gefehlt, daß man ein wenig Scripten kann.

    Sehr hübsch als Basis wäre auch http://www.windowsgames.co.uk/slay.html
    Derselbe Autor haut auch ein klassisches Empire raus http://www.windowsgames.co.uk/mother.html

    Spannend fände ich, das http://en.wikipedia.org/wiki/Prisoner's_dilemma aufzusetzen. Extrem einfaches Framework. Und ich würde gerne wissen, on Tit For Tat wirklich so gut ist. Mir scheint, die Forschung ist dahingehend eingeschlafen.



  • Vielleicht irgend ein Kartenspiel?

    Edit: Achja, bitte mal irgendwas, wo ich auch ne Chance habe, da Programm mal hinzubekommen 😃


  • Administrator

    Mathematische Probleme in eingeschränkter Zeit mit bestmöglichem Ergebnis zu lösen sind auch immer wieder nette Aufgaben. Zum Beispiel gab es doch letzten was bei Spieleprogrammierer.de, wo eine Karte bestmöglichst in Nord und Süd aufgeteilt werden musste.
    http://www.spieleprogrammierer.de/32-programmier-contests/16101-14-planetenteilung-spezial-14-08-2011/

    Hauptproblem bei Contests ist halt immer dasselbe. Irgendwer muss es organisieren und das kostet meistens Zeit. Und am Ende wird es oft nicht mal gebührend geschätzt 😉

    Grüssli



  • So, der nicht optimierende Compiler läuft (knabbert gerade an "Primes100 (indirect)". Die Implementierung ist wie erwartet trivial 😉



  • Generierst Du IL-Code?

    Her mit dem Code.



  • BTW: ich hatte zwar erst vorgeschlagen IL Code zu generieren, das ist aber eigentlich doof.
    Erstmal hat der C# Compiler vermutlich selbst nen ganz netten Optimizer, den man nicht verschwenden sollte, und zweitens ist die Fehlersuche sicher einfacher, wenn man C# Code generiert statt IL Code.
    Bzw. auch die Suche nach neuen Patterns die man dem eigenen Optimizer anlernen könnte wird dadurch vermutlich viel einfacher.



  • OK, hier der erste lauffähige Versuch. CompilingEvaluator nimmt die Rolle des Interpreters ein, d.h. starten mit new TestSession<Brainfuck.CompilingEvaluator>().Run(); . Das Interface S musste ich public machen. Ob es auch ohne geht, weiß ich nicht, dazu müsste man den Code ja in dasselbe Assembly generieren.

    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Collections.Generic;
    
    namespace Brainfuck
    {
        class SimpleCompiler
        {
            private static void GenerateCode(string program, MethodBuilder mBuilder)
            {
                ILGenerator ilgen = mBuilder.GetILGenerator();
    
                // Note: the types can't be changed arbitrarily. The Load and Store instructions have to be adjusted as well.
                Type pointerType = typeof(uint);
                Type dataType = typeof(short), dataArrayType = typeof(short[]);
                int dataSize = 32768;
    
                // Declare and initialize data pointer
                LocalBuilder pointer = ilgen.DeclareLocal(pointerType, false);
                ilgen.Emit(OpCodes.Ldc_I4_0);
                ilgen.Emit(OpCodes.Stloc, pointer);
    
                // Declare and initialize data array
                LocalBuilder dataArray = ilgen.DeclareLocal(dataArrayType, false);
                ilgen.Emit(OpCodes.Ldc_I4, dataSize);
                ilgen.Emit(OpCodes.Newarr, dataType);
                ilgen.Emit(OpCodes.Stloc, dataArray);
    
                // Declare parameter
                ParameterBuilder systemParam = mBuilder.DefineParameter(1, ParameterAttributes.In, "s");
    
                // Manage labels:
                // [ creates two labels: one for the current instruction and one for the instruction after the loop
                // ] jumps to the corresponding top of stack and marks the other one
                Stack<Label> labelStack = new Stack<Label>();
    
                for (int i = 0; i < program.Length; ++i)
                {
                    switch (program[i])
                    {
                        case '<':
                            // Decrease data pointer
                            ilgen.Emit(OpCodes.Ldloc, pointer);
                            ilgen.Emit(OpCodes.Ldc_I4_1);
                            ilgen.Emit(OpCodes.Sub);
                            ilgen.Emit(OpCodes.Stloc, pointer);
                            break;
    
                        case '>':
                            // Increase data pointer
                            ilgen.Emit(OpCodes.Ldloc, pointer);
                            ilgen.Emit(OpCodes.Ldc_I4_1);
                            ilgen.Emit(OpCodes.Add);
                            ilgen.Emit(OpCodes.Stloc, pointer);
                            break;
    
                        case '+':
                            // Increase current data
                            // Prepare Store
                            ilgen.Emit(OpCodes.Ldloc, dataArray);
                            ilgen.Emit(OpCodes.Ldloc, pointer);
    
                            // Load current data
                            ilgen.Emit(OpCodes.Ldloc, dataArray);
                            ilgen.Emit(OpCodes.Ldloc, pointer);
                            ilgen.Emit(OpCodes.Ldelem_I2);
    
                            // Increase
                            ilgen.Emit(OpCodes.Ldc_I4_1);
                            ilgen.Emit(OpCodes.Add);
    
                            // Now the result is on top of the stack, store it
                            ilgen.Emit(OpCodes.Stelem_I2);
                            break;
    
                        case '-':
                            // Decrease current data
                            // Prepare Store
                            ilgen.Emit(OpCodes.Ldloc, dataArray);
                            ilgen.Emit(OpCodes.Ldloc, pointer);
    
                            // Load current data
                            ilgen.Emit(OpCodes.Ldloc, dataArray);
                            ilgen.Emit(OpCodes.Ldloc, pointer);
                            ilgen.Emit(OpCodes.Ldelem_I2);
    
                            // Increase
                            ilgen.Emit(OpCodes.Ldc_I4_1);
                            ilgen.Emit(OpCodes.Sub);
    
                            // Now the result is on top of the stack, store it
                            ilgen.Emit(OpCodes.Stelem_I2);
                            break;                
    
                        case '[':
                            {
                                // Enter loop if current data != 0, skip loop otherwise
                                Label thisInstruction = ilgen.DefineLabel();
                                Label followingInstruction = ilgen.DefineLabel();
    
                                // Push two labels:
                                // thisInstruction: label to which the corresponding ] has to jump
                                // followingInstruction: label of the instruction after the corresponding ]
                                // only thisInstruction will be marked here
                                labelStack.Push(thisInstruction);
                                labelStack.Push(followingInstruction);
                                ilgen.MarkLabel(thisInstruction);
    
                                // Load current data
                                ilgen.Emit(OpCodes.Ldloc, dataArray);
                                ilgen.Emit(OpCodes.Ldloc, pointer);
                                ilgen.Emit(OpCodes.Ldelem_I2);
    
                                // Compare with 0 and branch
                                ilgen.Emit(OpCodes.Ldc_I4_0);
    
                                ilgen.Emit(OpCodes.Beq, followingInstruction);
                            }
                            break;
    
                        case ']':
                            {
                                // Jump to the beginning of the loop
                                // (Alternative implementation: Exit loop if current data == 0, jump to the beginning otherwise)
    
                                // Pop two labels:
                                // nextInstruction is the instruction after the loop, marked here
                                // loopBegin is the label that was marked when translating the corresponding [
                                Label nextInstruction = labelStack.Pop();
                                Label loopBegin = labelStack.Pop();
                                ilgen.Emit(OpCodes.Br, loopBegin);
                                ilgen.MarkLabel(nextInstruction);
                            }
                            break;
    
                        case '.':
                            {
                                // Write current data: 
                                // Call s.W(dataArray[pointer])
                                MethodInfo writeMethod = typeof(S).GetMethod("W");
                                ilgen.Emit(OpCodes.Ldarg, 1);
    
                                // Load current data
                                ilgen.Emit(OpCodes.Ldloc, dataArray);
                                ilgen.Emit(OpCodes.Ldloc, pointer);
                                ilgen.Emit(OpCodes.Ldelem_I2);
    
                                // Call shell.W
                                ilgen.Emit(OpCodes.Call, writeMethod);
                            }
                            break;
    
                        case ',':
                            {
                                // Read into current data: 
                                // Call s.R() and assign the result to dataArray[pointer]
                                MethodInfo readMethod = typeof(S).GetMethod("R");
    
                                // Prepare Store
                                ilgen.Emit(OpCodes.Ldloc, dataArray);
                                ilgen.Emit(OpCodes.Ldloc, pointer);
    
                                // Call shell.R()
                                ilgen.Emit(OpCodes.Ldarg, 1);
                                ilgen.Emit(OpCodes.Call, readMethod);
    
                                // Assign result
                                ilgen.Emit(OpCodes.Stelem_I2);
                            }    
                            break;
                    }
                }
                ilgen.Emit(OpCodes.Ret);
            }
    
            public static void CompileAndRun(S system)
            {
                AssemblyName asmName = new AssemblyName("Brainfuck");
                AssemblyBuilder asmBuilder = 
                    System.Threading.Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
                ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("Brainfuck.exe");
                TypeBuilder typeBuilder = modBuilder.DefineType(
                    "Brainfuck", 
                    TypeAttributes.Public | TypeAttributes.Class);
    
                MethodBuilder runMethodBuilder = typeBuilder.DefineMethod(
                    "Run",
                    MethodAttributes.HideBySig | MethodAttributes.Public,
                    typeof(void),
                    new Type[] { typeof(S) });
    
                GenerateCode(system.P, runMethodBuilder);
    
                Type brainfuckTempType = typeBuilder.CreateType();
                MethodInfo runMethod = brainfuckTempType.GetMethod("Run");
                ConstructorInfo ctor = brainfuckTempType.GetConstructor(Type.EmptyTypes);
    
                Object compiledProgram = ctor.Invoke(new object[] {});
                runMethod.Invoke(compiledProgram, new object[] { system });
            }
        }
    
        class CompilingEvaluator
        {
            public void R(S s)
            {
                SimpleCompiler.CompileAndRun(s);
            }
        }
    }
    

    hustbaer: Das sagst du jetzt! 😃 Ich hatte mir das erst auch ein bisschen anders vorgestellt, nicht daran gedacht, dass das ja eine Stackmaschine ist.


Anmelden zum Antworten