Sign in to follow this  
  • entries
    5
  • comments
    7
  • views
    11639

About this blog

A journal (usually) about .NET, Graphics, and other... things...

Entries in this blog

YellPika
Mirrored from my blog.

Things have been pretty busy lately. Over the summer, I got my first job working as a programmer. A little over a month ago, I began attending university (first year). While the experiences thus far have been excellent on both counts, there have been a couple unfortunate downsides:


  1. I've barely had any time to blog. Not such an issue, since my writing sucks anyway :-)
  2. I've had absolutely no time to sit down and write a game (!!!)


Surely I can't be that busy... can I? There's another reason: I've become totally addicted to functional programming. The traditional rendering APIs don't lend themselves well to a functional style, and I've spent a lot of time pondering how I can twist them to suit my desires. I began working on some rough sketches of possible wrapper APIs, and attempted to implement some of them without much success.

I have come to realize that I can't do it like that. Trying to design a rendering API without any particular game in mind is... hard. What exactly is needed? What features do I need to support? How do I design it in such a way that the necessarily impure functionality is separated from the pure? There's a target, but it's far away. I can try to shoot now, but I'd probably miss. I need to get closer, and it would seem the best way to do that is to write more games in functional languages.

In other words, actually get something done.

Bearing this in mind, I once again venture into the fantastic world of game programming...

John Conway's Game of Life


(This counts as a game, right?)

I have to say, F# is pretty damn good. Interopability with the other languages on the .NET frameworks seems like it could use some work (how about you try passing a function object from C# to F#?) but overall it's quite nice. I miss Haskell's epically powerful type system, but I suppose it can't be helped.

So here you go. The Game of Life, entirely in F#:


open System

// int -> int -> bool [,]
//
// Creates a width * height grid of boolean values which
// are randomly initialized to true or false
let Create width height =
let random = Random()
Array2D.init width height (fun _ _ -> random.Next() % 2 = 0)

// bool [,] -> int -> int -> int
//
// Computes the number of live neighbors in a 9x9 grid surrounding (x, y)
let Neighbors grid x y =
// Create the 9x9 grid
[for u in x - 1 .. x + 1 do
for v in y - 1 .. y + 1 do
yield u, v]

// Ignore the current cell (the centre of the 9x9 grid)
|> List.filter (fun (u, v) -> u <> x || v <> y)

// Ensure that all the coordinates are within the bounds of the array
|> List.filter (fun (u, _) -> 0 <= u && u < Array2D.length1 grid)
|> List.filter (fun (_, v) -> 0 <= v && v < Array2D.length2 grid)

// Count the number of live cells
|> List.filter (fun (u, v) -> grid.[u, v])
|> List.length

// bool [,] -> int -> int -> bool
//
// Determines whether a cell should be dead or alive in
// the next frame of the simulation.
let IsAlive grid x y =
match Neighbors grid x y with
| 3 -> true
| 2 -> grid.[x, y]
| _ -> false

// bool [,] -> bool [,]
//
// Advances the simulation by one frame
let Update grid =
Array2D.mapi (fun x y _ -> IsAlive grid x y) grid

// bool [,] -> string
//
// Converts a grid of cells to a suitable string representation
// for printing to the console
let Show grid =
[for y in 1 .. Array2D.length2 grid do
for x in 1 .. Array2D.length1 grid do
match grid.[x - 1, y - 1] with
| true -> yield "O"
| false -> yield " "
yield "\n"]
|> String.Concat

// bool [,] -> unit
//
// Renders a grid of cells to the console
let Render grid =
Console.SetCursorPosition(0, 0)
Console.WriteLine(Show grid) // WriteLine is much faster than printf

// Create, simulate and render a grid until the user presses a key.
Create 70 20
|> Seq.unfold (fun x -> Some (x, Update x))
|> Seq.takeWhile (fun _ -> not Console.KeyAvailable)
|> Seq.iter Render


Wow, eh? Excluding the comments, the program is a little over 50 lines long. Considering that (almost?) everything in F# is an expression, I could probably reduce this to a couple lines with little effort. Not that I'd every want to do that...

So what have I learned from this?


  1. The console can actually render things pretty quickly. I don't know what kind of frame rate I was getting, but the entire simulation would usually "finish" in around 5 - 30 seconds. I know that's a pretty big range, but this thing can go on for ages if the starting conditions are right.
  2. The rendering function could be abstractly defined as a function which simply takes in a description of what needs to be rendered, and returns nothing. This is in contrast to previous ideas I had about "functionalizing" the rendering pipeline, where I would repeatedly pipe the "render target" (which was really just a list of rendering commands) through a series of functions which would "transform" the current render target (i.e. add a command to the list) and return a new copy. Perhaps this idea will be more appealing when I get to more complex visuals?
  3. Game logic, user input, and rendering can be separated from rendering quite easily (at least for this example). Take a look at the last statement - see how each line corresponds to exactly one of the aforementioned tasks?


    Game Logic: Seq.unfold (fun x -> Some (x, Update x))
    User Input: Seq.takeWhile (fun _ -> not Console.KeyAvailable)
    Rendering: Seq.iter Render



It's not much, but it's a start. The plan is to slowly implement games with increasing complexity, and document my observations about their implementations. So what should I implement next?

The name's Pong. Console Pong.

Gah, sorry. Until next time.

YellPika
YellPika
Mirrored from my blog.

Last post I demonstrated how to make a simple command prompt using a basic Console project. This time I'm going to show how to embed one in a window.

I'll admit it, getting this to work was not particularly easy. I tried a number of different methods, from redirecting the output stream to parenting the console window. Redirecting the output stream didn't work because not all of the output could be read until the program finished executing. Parenting the console window didn't work because it wouldn't draw correctly when I removed the border. In the end, I had to copy the text from the console buffer itself.

Hooray, more P/Invoke.

Reading from the Console Window

There are few functions defined for manipulating console windows. Luckily, none of them have been wrapped. The most important ones are GetStdHandle and ReadConsoleOutputCharacter. The P/Invoke definitions are as such:
[source lang=csharp]
[StructLayout(LayoutKind.Sequential)]
private struct COORD
{
public short X;
public short Y;

public COORD(short X, short Y)
{
this.X = X;
this.Y = Y;
}
};

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32.dll")]
private static extern bool ReadConsoleOutputCharacter(IntPtr hConsoleOutput, [Out] char[] lpCharacter, uint nLength, COORD dwReadCoord, out uint lpNumberOfCharsRead);
[/source]
GetStdHandle is used to get the handle to the standard output stream. That is then passed as the first argument to ReadConsoleOutputCharacter, which is the actual function for reading from the console output.

The annoying thing about reading from the console is that there are no line breaks. If you use ReadConsoleOutputCharacter to read the whole console at once, it gives you one huge line of text. Also, the console buffer is a fixed size - it doesn't expand when you write more text, it overwrites whatever's at the cursor. Ever wonder why, when you open the command prompt, you can scroll so far down even though there's nothing written? Those are all spaces.

The best solution I could come up with was to read the console one line at a time, adding the breaks and trimming the lines as you go.
[source lang=csharp]
var text = new StringBuilder();

for (int i = 0; i < Console.BufferHeight; i++)
text.AppendLine(GetLine(i));

var output = text.ToString().TrimEnd();

// elsewhere

private string GetLine(int line)
{
uint garbage;
if (!ReadConsoleOutputCharacter(handle, buffer, (uint)buffer.Length, new COORD(0, (short)line), out garbage))
throw new InvalidOperationException("Could not read console output.");

return new string(buffer).TrimEnd();
}
[/source]
That's all that's necessary to read directly from the console window. Just one little gotcha - there's no way (that I know of) to tell if the console has been updated with more text. It has to be constantly read and reread. Also, the reading process can be quite slow. My solution was to do the reading in a separate thread. Here is the whole ConsoleReader class.
[source lang=csharp]
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

public sealed class ConsoleReader
{
#region Interop
[StructLayout(LayoutKind.Sequential)]
private struct COORD
{
public short X;
public short Y;

public COORD(short X, short Y)
{
this.X = X;
this.Y = Y;
}
};

[DllImport("kernel32")]
static extern bool AllocConsole();

[DllImport("kernel32.dll")]
private static extern bool ReadConsoleOutputCharacter(IntPtr hConsoleOutput, [Out] char[] lpCharacter, uint nLength, COORD dwReadCoord, out uint lpNumberOfCharsRead);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
#endregion

private IntPtr handle;
private char[] buffer;

public string Text { get; private set; }
public bool IsInitialized { get; private set; }

public ConsoleReader()
{
AllocConsole();
ShowWindow(FindWindow(null, Console.Title), 0); // Hides the console.

handle = GetStdHandle(-11); // -11 is the standard output stream. Odd number to use...
buffer = new char[Console.BufferWidth];

Text = "";

IsInitialized = true;
AppDomain.CurrentDomain.ProcessExit +=
(sender, e) => IsInitialized = false;
ThreadPool.QueueUserWorkItem(n => UpdateThread());
}

private void UpdateThread()
{
while (IsInitialized)
{
var textBuilder = new StringBuilder();

for (int i = 0; i < Console.BufferHeight; i++)
textBuilder.AppendLine(GetLine(i));

Text = textBuilder.ToString().TrimEnd();
}
}

private string GetLine(int line)
{
uint garbage;
if (!ReadConsoleOutputCharacter(handle, buffer, (uint)buffer.Length, new COORD(0, (short)line), out garbage))
throw new InvalidOperationException("Could not read console output.");

return new string(buffer).TrimEnd();
}
}
[/source]
And that's that.

Displaying the Text

I'll confess right now: I cheated. I used two textboxes, one for input and one for output. After spending a good length of time just trying to figure out how to read from the console, I was too lazy to have both input and output in one box. Sorry :P.

It's pretty straightforward from here. Place one textbox across the bottom, then another filling the rest of the space. Create a timer that retrieves the console input at a small interval. Check for any differences between the new and old text. Remember to scroll to the end if there are. Go take a nap.

Running Processes

Calling system isn't going to work here anymore, specifically for processes that ask for input while they run. Without any direct access to the console, how is the process supposed to receive input? Back to the Process class...

If you set UseShellExecute to false, but don't redirect the standard error and output streams, they will automatically show up in the console window. The input stream can be redirected without consequence.

I created a simple class for executing processes, and will redirect the command to any process already running.

[source lang=csharp]
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

public sealed class CommandRunner
{
private Process process;

public event EventHandler Finished;
public event EventHandler ExitCommandRecieved;

public void Execute(string command)
{
Console.WriteLine(command);

if (process != null)
SendToProcess(command);
else if (command.TrimStart().StartsWith("cd "))
ChangeDirectory(command);
else if ((command.Trim() + " ").StartsWith("exit "))
InvokeExit();
else
StartProcess(command);
}

private void InvokeExit()
{
if (ExitCommandRecieved != null)
ExitCommandRecieved(this, EventArgs.Empty);
}

private void ChangeDirectory(string command)
{
var directory = command.Split(new[] { ' ' }, 2)[1].Replace("\"", "");

if (Directory.Exists(directory))
Directory.SetCurrentDirectory(directory);
else
Console.WriteLine("The system cannot find the path specified.");

if (Finished != null)
Finished(this, EventArgs.Empty);
}

private void StartProcess(string command)
{
var filename = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "temp.bat");

File.WriteAllText(filename, "@echo off\n" + command);

process = new Process()
{
EnableRaisingEvents = true,
StartInfo = new ProcessStartInfo(filename) { UseShellExecute = false, RedirectStandardInput = true },
};

process.Exited +=
(sender, e) =>
{
process = null;
File.Delete(filename);

if (Finished != null)
Finished(null, EventArgs.Empty);
};

process.Start();
}

private void SendToProcess(string command)
{
process.StandardInput.WriteLine(command);
}
}
[/source]
And so I draw this mess to a close. That should cover everything necessary to emulate a console. With this out of the way I can get back to working on my normal graphics-related projects...

If there's anything that could be improved, in writing or in code, feel free to let me know.

YellPika
YellPika
Mirrored from my blog.

The school I go to places ridiculous restrictions on the computers. Right clicks aside, one thing I wish above all things they hadn't disabled was the command prompt. Ironically, the computers also have support for a number of programming languages. A friend of mine managed to emulate one using Python, and all was swell. The best part was that he coded in functionality to automatically add things to the system path. You see, we were doing quite a bit of C++/MinGW at the time... off our USBs of course.

I decided to make my own. The Python script had the added bonus of being cross platform, but it would be quite the stretch to expect every Windows machine in the world to have Python installed. I wanted my own custom command prompt. Because I rarely use Mac/Linux, .NET is installed on all up-to-date Windows machines, and it's simply an awesome language, I decided to use C#.

Basic Command Prompt

Creating a basic command prompt is easy. Being a simple program, I broke my practices and shoved most of the code in the Main method, but here it is:
[source lang=csharp]
public static void Main(string[] args)
{
while (true)
{
Console.Write(Directory.GetCurrentDirectory() + ">");

var input = Console.ReadLine().Trim();

if (input.Length >= 2 && input.Substring(0, 2).ToLower() == "cd")
ChangeDirectory(input);
else if (input.ToLower() == "exit")
break;
else
system(input);
}
}
[/source]
There are two special cases checked for before doing normal processing of the input command. The first is a cd command. This has to be handled manually, and is fairly simple to do. The second is an exit command.

The last bit is how I actually execute the input command, provided it isn't one of the special cases mentioned above. The are a couple of ways I could have done it. The first would be using the System.Diagnostics.Process class, invoking an instance of cmd.exe, and passing the command to that. As mentioned before, the Command Line is blocked on the school computers, so I wasn't sure that would work. Another alternative was writing the command to a batch file, then executing it. However, I wanted a simpler way to do it, one without using the Process class.

This leads to the system method. C++ programmers will recognize it - it's most common use seems to be 'system("pause")'. It's general purpose is to run commands. The P/Invoke definition for it is as such:
[source lang=csharp]
[DllImport("msvcrt.dll", SetLastError = true)]
public static extern void system(string command);
[/source]
It's simple, and works wonderfully. All output is properly redirected to the program's console.

Now for the kicker - easily adding values to the system path. To do this, I defined a method:
[source lang="csharp"]
private static void AddToSystemPath(string path)
{
var current = Environment.GetEnvironmentVariable("PATH");
Environment.SetEnvironmentVariable("PATH", path + ";" + current);
}
[/source]
And modified the main if-block:
[source lang=csharp]
if (input.Length >= 2 && input.Substring(0, 2).ToLower() == "cd")
ChangeDirectory(input);
else if (input.ToLower() == "exit")
break;
else if (input.Length > 8 && input.Substring(0, 8).ToLower() == "addpath ")
AddToSystemPath(input.Split(new[] { ' ' }, 2)[1]);
else
system(input);
[/source]
Voila. A giant mess. Look at all those random numbers, those nonsensical lines of code without even a comment. Time to clean up...

...except I never got to that. I had a better idea. A lot of my development tools are portable - I could stick them on my USB stick. Why don't I make an application which can give me easy access to all my applications and files, allow me to easily edit the system path, and provide me a command prompt? And so, I ditched my makeshift command line for this monstrosity, the aptly named Flash Centre:
image.png
Hey look, I finally learned some WPF!!

Next post, I'll describe how I managed to emulate a command prompt in a textbox, and the various issues I had to put up with.

YellPika

EDIT: Just noticed that some things did not paste properly into the post. I believe everything is fixed now.
YellPika
While developing spectral, I discovered something peculiar.

Consider this sample pseudo C#/IL:

public static T Sqrt(T value)
{
ldarg.0
conv.r8
call double System.Math.Sqrt(double)
ret
}

You'd expect some sort of error, right? The return type is T, but the returned value is a double.
Turns out it runs fine. What's more, you don't even need the conv.r8 instruction.

I have to say, IL's flexibility is amazing.

YellPika
YellPika
Hrm... first post. This actually contains content from my blog, but I felt like writing it again, differently.
[hr]
It's a problem that's been tackled a hundred, billion times. My personal favourites are this and this. The first, however, I felt required too much code, and the second was too slow (disclaimer: I never tried it myself - apparently the JIT inlines the code, resulting in a very small performance difference). Then I had an idea.

Coding in IL, what if I were to force the usage of an add instruction, regardless of the input type? Ex (pseudo C#/IL here):

public static void Add(T left, T right)
{
ldarg.0
ldarg.1
add
ret
}

Testing, testing... well, what do you know, it works!! Not that I know anything about micro-benchmarking, but the performance was roughly the same as regular code (a little slower, which I assume was due to some type checking code I added).

Thus, the beginnings of a potentially awesome math (why am I getting red squiggles under this word?) library. Eventually, I produced this:

public static class Operator
where T : struct, IEquatable, IComparable
{
static Operator()
{
var type = typeof(T);
if (!type.IsPrimitive || type == typeof(bool) || type == typeof(char))
throw new ArgumentException("The specified type is not supported.", "T");
}

public static T Add(T left, T right) { return default(T); }
public static T Subtract(T left, T right) { return default(T); }

// etc
}

At post-compile time, I had a separate program rewrite the methods with the appropriate code using Mono.Cecil.

You may have noticed that I restricted the type to non-bool/char primitive types. You may also notice that the int/float/double/etc. types don't actually have any operators defined. The compiler handles them for you - that's what the add instruction is for. As such, this [s]hack [/s] trick only works on primitive types. All primitive types, and that includes bool and char. Since it's rather... impractical... to add two booleans together, I decided to filter them out too (by the way, a + b = [font="sans-serif"][size="2"]A).[/font]

[font="sans-serif"][size="2"]For those who want to get their hands on some source code, I stuck all this into a project on Codeplex. It's largely incomplete, but I'm working on it. Enjoy.[/font]

[font="sans-serif"][size="2"]YellPika[/font]
Sign in to follow this