Home

AirMess – Release 3

April 14, 2014

The 3rd iteration of AirMess just hit the Windows Store :)

AirMess

Get AirMess (Windows 8.1)

 

What’s in the box?

  • You can now chose between several ships. Currently they don’t act completely differently, but that will come :)
  • You can launch MISSILES!
  • There’s a Driver Assist which can help you on the slowest class

Have fun!

 

PS. On an unrelated notice, AirMess (the game) is built as a portable library. Meaning? even though it’s released as a Windows Store app, I can still run it in a good old WinForms window ;)
AirMess Desktop

AirMess Ships

April 4, 2014

AirMess Ships

It’s coming!

After an ImagineCup project, a reboot, a new job, a new country and months of silence, AirMess is finally available in the Windows Store!

AirMess

Get AirMess (Windows 8.1)

 

It’s still in a very early stage (even compared to the previous ImagineCup project), but hopefully there will be incremental on a regular basis.

 

Already  in the pipe for the next release, more ships (and maybe more technical details about how that happened :))

And of course, SharpDX rocks!

 

yield is a very useful keyword in C# that allows you to create dynamic enumerators of stuffs without having to fill in a List<T> of things you want to return first. The generated code builds a state machine that will go forward, step by step, whenever the caller calls MoveNext on the IEnumerable it gets back (usually using foreach).

        static void Main(string[] args)
        {
            var input = new[] { "A", "B", "C" };

            Console.WriteLine(String.Join("\n", Process(input)));
        }

        static IEnumerable<string> Process(IEnumerable<string> input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            foreach (var item in input)
            {
                yield return "Process " + item;
            }
        }

        // Output :
        // Process A
        // Process B
        // Process C

The second really useful thing is Parallel.ForEach. Whenever you have to process loads of independent data that are CPU hungry you can launch the process in parallel and have it scheduled for you by the .NET runtime.

        static void Main(string[] args)
        {
            var input = new[] { "A", "B", "C" };

            Stopwatch w = new Stopwatch();
            w.Start();
            Process(input);
            w.Stop();

            Console.WriteLine("{0}s ", w.Elapsed.TotalSeconds);
        }

        static void Process(IEnumerable<string> input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            Parallel.ForEach(input, item =>
                {
                    // Something long
                    Thread.Sleep(1000);
                });
        }
        
        // Output :
        // ~ 1s although we had 3 stuffs that each took 1s

What if we could write that?

        static void Main(string[] args)
        {
            var input = new[] { "A", "B", "C" };

            Stopwatch w = new Stopwatch();
            w.Start();
            var result = Process(input);
            w.Stop();

            Console.WriteLine("{0}s ", w.Elapsed.TotalSeconds);
            Console.WriteLine(String.Join("\n", result));
        }

        static IEnumerable<string> Process(IEnumerable<string> input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            Parallel.ForEach(input, item =>
                {
                    // Something long
                    Thread.Sleep(1000);
                    
                    // >>>> THE POWER !!
                    yield return "Process " + item;
                });
        }

But no we can’t because “The yield statement cannot be used inside an anonymous method or lambda expression“.
You obviously can’t mix those two pieces of magic together. In fact, if we could this would produce some of the weirdest bugs ever if something went wrong. But maybe we can’t build something that looks like it, for the sake of doing it?

        static void Main(string[] args)
        {
            var input = new[] { "A", "B", "C" };

            Stopwatch w = new Stopwatch();
            w.Start();
            var result = Process(input);

            Trace.WriteLine(String.Format("{0}s before enumerating", w.Elapsed.TotalSeconds));
            Trace.WriteLine(String.Format(String.Join("\n", result)));
            Trace.WriteLine(String.Format("{0}s after enumerating", w.Elapsed.TotalSeconds));
        }

        static IEnumerable<string> Process(IEnumerable<string> input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            var workQueue = new ConcurrentQueue<string>();
            Exception workException = null;
            var completed = false;

            // This task will run on its side in another thread
            Task.Run(() =>
            {
                try
                {
                    Parallel.ForEach(input, item =>
                        {
                            // Something long
                            Thread.Sleep(1000);

                            // Push our results here
                            workQueue.Enqueue("Process " + item);
                        });
                }
                catch (Exception ex)
                {
                    // We don't want a crash to be lost in another thread
                    // so we have to bring it back somehow on the main thread
                    workException = ex;
                }

                completed = true;
            });

            // Not the most elegant, but it's just for fun so ...
            while (!completed)
            {
                string item;
                if (workQueue.TryDequeue(out item))
                    yield return item;
                else
                    Thread.Sleep(1); // remember, just for fun
            }

            // We don't want to lose the last items
            string finalItem;
            while (workQueue.TryDequeue(out finalItem))
                yield return finalItem;

            // Buble the exception if there's one
            if (workException != null)
            {
                throw new Exception("Error while doing stuffs", workException);
            }
        }

Output:

0.00039s before enumerating
Process B
Process A
Process C
1.0398348s after enumerating

Notice than we did have an “yield behavior” as the processing was not executed on the call to Process, and how the whole process took 1s where it has 3 items that each took 1s. We also don’t have a reliable order anymore, it could have been any combination of B, A and C.

But anyway, nailed it :)

Just for fun, here’s AirMess, as it was presented for ImagineCup France 2012 Finals.

AirMess ScreenShoot  1

AirMess ScreenShoot  2

AirMess ScreenShoot  3

Note that it’s a .ccgame.
To be able to install it, you’ll need Microsoft XNA Framework Redistributable 4.0

Have fun ;)

I always wanted to try GPGPU programming but never had the opportunity and doing business applications in .NET doesn’t really helps doing that (still, there are people doing this in high frequency trading applications but that’s not my case).

But for a game, this is completely different.

Read the rest of this entry »

Say you have state defining struct you want to be copy:

 

        public struct MyStruct
        {
            public int A;
        }

Then use it like that:

            var S0 = new MyStruct();
            S0.A = 42;

            var S1 = S0;
            S1.A = 1337;

            Trace.WriteLine(String.Format("S0 = {0}, S1 = {1}", S0.A, S1.A));

The output is: S0 = 42, S1 = 1337
Even though S1 = S0, because it’s a struct it was copied. If I replace struct by class I get S0 = 1337, S1 = 1337. Everything’s normal.

Let say I want to have an array in this struct:

        public struct MyStruct
        {
            // Can't initialize the array directly
            public int[] A;

            // We can't customize the parameterless constructor
            public MyStruct(int size)
            {
                A = new int[size];
            }
        }

        var S0 = new MyStruct(1);
        S0.A[0] = 42;

        var S1 = S0;
        S1.A[0] = 1337;

        Trace.WriteLine(String.Format("S0 = {0}, S1 = {1}", S0.A[0], S1.A[0]));

The output is … S0 = 1337, S1 = 1337
That’s because the reference to the array was copied in the struct, not the actual value.
How can we have the array inside the struct?

        public unsafe struct MyStruct
        {
            public fixed int A[1];
        }

        unsafe static void Main(string[] args)
        {
            var S0 = new MyStruct();
            S0.A[0] = 42;

            var S1 = S0;
            S1.A[0] = 1337;

            Trace.WriteLine(String.Format("S0 = {0}, S1 = {1}", S0.A[0], S1.A[0]));
        }

And I get S0 = 42, S1 = 1337. But there are 2 problems in this approach.

  • You now have to build everything using the unsafe keyword because now A is a int*
  • This works:
                var S0 = new MyStruct();
                S0.A[1] = 42;
    
                var S1 = S0;
                S1.A[1] = 1337;
    
                Trace.WriteLine(String.Format("S0 = {0}, S1 = {1}", S0.A[1], S1.A[1]));
    

    .
    Even though my array is 1 element long, I was able to access the second in-existent element and change it. That’s a buffer overflow: because my array is now unsafe, the runtime no longer checks the boundaries of my array and I can access memory outside my allowed space.

What would be cool is if I was able to write that:

        public struct MyStruct
        {
            // hey C# compiler, create 10 int fields in my struct (from A0 to A9) and translate S0.A[i] to S0.Ai for me
            public int A[10];
        }

Btw I realize this wouldn’t work for some cases like, what should happen if we pass this A as a parameter for a method call expecting a regular array? If we try to store the A in a local int[], what would be in that variable? A new copy of this array? The address of that array in the struct that might be allocated on the stack? How should we track that reference?

But anyway, we can dream :)

Follow

Get every new post delivered to your Inbox.

Join 34 other followers