MorkaLork Development

Interesting stuff I've picked up over the years...

C# Console Matrix

2010-01-10 14:39:16 | 1045 views | C# matrix console flow application

What is the matrix?


According to idiots, you cannot be told what the matrix is, you have to see it for yourself. Fortunately, with the help of C#, we can see what it is by creating a console application that displays it to us.

The matrix is just a random flow of numbers which means we can use the C# Random class to create the numbers. The flowing effect can be created by setting of a certain number of threads to display these silly numbers one by one while jumping down one step after every output.

This is what we will do, and the end result will look like this:

The matrix in C# console form

Of course, we could make it look better, but this tutorial will only show you how to create the base matrix.


What do I need to know?


Here's a little list of things that could be good to know before creating the matrix:



Let's get started...


All in all, this program will end up as 70 lines of code, that's it. Why? Because we will use threading to create this matrix. You might have seen other matrix applications where one single thread franticly runs around the console window painting the matrix. We won't, we are lazy and we want to be efficient.

Actually, there will only be 4 methods (and that's only because I chose to refactor two snippets):

Main()
RunMatrix()
getRandomX()
getRandomY()


The last two methods are used to obtain a random console coordinate so to prevent all 20 threads to starting writing on the same line (hopefully).

It is the RunMatrix() method that is the most important, so we'll start there:



static void RunMatrix(object obj) {
//Since we know that the object being sent in is a Random object,
//we just shift it...
Random random = obj as Random;

//Get starting coordinate values
int x = getRandomX(random);
int y = getRandomY(random);

//This is how fast the letters will move, in milliseconds
int speed = random.Next(60, 100);

//These are the colors to use on the screen. Green is Matrix style,
//but they can of course be changed
ConsoleColor lightColor = ConsoleColor.Green;
ConsoleColor darkColor = ConsoleColor.DarkGreen;

while (true) {

int digitToOutput = random.Next(0, 9);
//This writes the letter with a bright light color
lock (syncLock) {
Console.SetCursorPosition(x, y);
Console.ForegroundColor = lightColor;
Console.Write(digitToOutput);
}

Thread.Sleep(speed);

//This overrites the previous letter with the proper dark color
lock (syncLock) {
Console.SetCursorPosition(x, y);
Console.ForegroundColor = darkColor;
Console.Write(digitToOutput);
}

if (y >= Console.WindowHeight - 1) {
x = getRandomX(random);
y = getRandomY(random);
}
//Move down one step for every loop
y++;
}
}


Right, this is basically it. The method takes a Random object in Object form. This is because the thread start() method will only accept parameters in the object form. However, since we know that the object sent in is a Random object we cast it as a Random object right away without any checks or anything.

After that we create two coordinate variables, x and y. These will be used to get a location on the console window. They call the getRandomX and getRandomY methods.
These methods are quite small and look like this:



static int getRandomX(Random r) {
return r.Next(0, Console.WindowWidth - 1);
}

static int getRandomY(Random r) {
return r.Next(0, Console.WindowHeight - 1);
}


The reason I refactored here is because they are used more than one time.

Anyway, now we have a random object and two coordinates. There are two more things we need before we can get started, a speed value and font colors.

The speed variable is and int which we set to a random value between 60 and 100 milliseconds. This can of course be changed, I thought it was a suitable speed for a matrix.
Then we set the font colors. Since the console class can't handle very complex colors we use Green and DarkGreen (we only need two colors for this matrix).

We are now ready to start the outputting.

The trick here is the following:
First, we output the digit in a bright green color. Then we wait for a while (the amount of speed), and then we output the same digit but in the darker color. After that we jump down one row and start over. This will give the matrix effect.
Of course, we make a check if we are at the bottom of the screen. If we are, we obtain a new starting coordinate.

Important here is that we use the lock() method. However, to understand why, we will take a look at the quite small Main method:


static void Main(string[] args) {
Random r = new Random();

Thread[] threads = new Thread[15];
for (int i = 0; i < threads.Length; i++) {
threads[italic] = new Thread(RunMatrix);
threads[italic].Start(r);
}

Console.Read();
}


That's it, that's all there is to it. What we do here is that we create 15 threads (and this can of course be altered to suit your needs) which all run the RunMatrix() method.

If we now go back to the RunMatrix() method we realize that we have 15 threads running the same static method. This means that we might end up with two or more threads trying to execute at the exact same time. However, this article is not about issue with threading. I might write one though, because it's interesting.
Sufficient to say we stay clear of this issue by locking the important parts in the RunMatrix to an Object object, syncLock. This means that only one thread at a time can access the locked parts of the RunMatrix() method.

You can try it out and see what happens if we don't do this by removing the lock. The result is quite interesting.

Anyhow. Here's the full source code, try it out:



using System;
using System.Threading;

namespace MorkaMatrix {
class Program {
static object syncLock = new object();

static void Main(string[] args) {
Random r = new Random();

Thread[] threads = new Thread[15];
for (int i = 0; i < threads.Length; i++) {
threads[italic] = new Thread(RunMatrix);
threads[italic].Start(r);
}

Console.Read();
}

static void RunMatrix(object obj) {
//Since we know that the object being sent in is a Random object,
//we just shift it...
Random random = obj as Random;

//Get starting coordinate values
int x = getRandomX(random);
int y = getRandomY(random);

//This is how fast the letters will move, in milliseconds
int speed = random.Next(60, 100);

//These are the colors to use on the screen. Green is Matrix style,
//but they can of course be changed
ConsoleColor lightColor = ConsoleColor.Green;
ConsoleColor darkColor = ConsoleColor.DarkGreen;

while (true) {

int digitToOutput = random.Next(0, 9);
//This writes the letter with a bright light color
lock (syncLock) {
Console.SetCursorPosition(x, y);
Console.ForegroundColor = lightColor;
Console.Write(digitToOutput);
}

Thread.Sleep(speed);

//This overrites the previous letter with the proper dark color
lock (syncLock) {
Console.SetCursorPosition(x, y);
Console.ForegroundColor = darkColor;
Console.Write(digitToOutput);
}

if (y >= Console.WindowHeight - 1) {
x = getRandomX(random);
y = getRandomY(random);
}
//Move down one step for every loop
y++;
}
}

static int getRandomX(Random r) {
return r.Next(0, Console.WindowWidth - 1);
}

static int getRandomY(Random r) {
return r.Next(0, Console.WindowHeight - 1);
}
}
}





Article comments

Feel free to comment this article using a facebook profile.

I'm using facebook accounts for identification since even akismet couldn't handle all the spam I receive every day.