Gigi Labs

Please follow Gigi Labs for the latest articles.
Showing posts with label ascii. Show all posts
Showing posts with label ascii. Show all posts

Monday, November 11, 2013

C# Security: Securing Passwords by Salting and Hashing

Hello and welcome, dear readers! :)

This article deals with storing passwords securely... usually in a database, but to keep things simple, we'll just use a C# dictionary instead. As part of this article, we'll cover two interesting techniques called salting and hashing. These topics can sometimes be challenging to understand - in fact you can see from my question about salting on StackOverflow that it had taken me a while to understand the benefits of salting, but it doesn't have to be that way. I am writing this article to hopefully make this fascinating subject easy to understand.

Right, so let's get to business. Create a new Console Application using SharpDevelop or whichever IDE you prefer. Add the following near the top, so that we can use dictionaries:

using System.Collections.Generic;

Just inside your class Program, before your Main() method, add the following dictionary to store our users and their corresponding passwords (see "C# Basics: Morse Code Converter Using Dictionaries" if this seems in any way new to you):

        public static Dictionary<String, String> users = new Dictionary<String, String>()
        {
            { "johnny""password" },
            { "mary""flowers" },
            { "chuck""roundhousekick" },
            { "larry""password123" }
        };

It is now pretty simple to add a method that can check whether a given username and password result in a successful login:

        public static bool Login(String username, String password)
        {
            if (users.ContainsKey(username) && users[username] == password)
                return true;
            else
                return false;
        }

This code first checks that the username actually exists in the dictionary, and then checks whether the corresponding password matches.

We can now test this code by replacing the contents of Main() with the following code:

        public static void Main(string[] args)
        {
            Console.Write("Username: ");
            String username = Console.ReadLine();
          
            Console.Write("Password: ");
            Console.ForegroundColor = ConsoleColor.Black;
            String password = Console.ReadLine();
            Console.ResetColor();
          
            bool loggedIn = Login(username, password);
            if (loggedIn)
                Console.WriteLine("You have successfully logged in!");
            else
                Console.WriteLine("Bugger off!");
          
            Console.ReadLine();
        }

Notice that when requesting the password, we're setting the console's text colour to black. The console's background colour is also black, so the password won't show as you type, fending off people trying to spy it while looking over your shoulder.

Press F5 to try it out:


Awesome - we have just written a very simple login system.

The problem with this system is that the passwords are stored as clear text. If we imagine for a moment that our usernames and passwords were stored in a database, then the actual passwords can easily be obtained by a hacker gaining illegal access to the database, or any administrator with access to the database. We can see this by writing a simple method that shows the users' data, simulating what a hacker would see if he managed to breach the database:

        public static void Hack()
        {
            foreach (String username in users.Keys)
                Console.WriteLine("{0}: {1}", username, users[username]);
        }

We can then add the following code just before the final Console.ReadLine() in Main() to test it out:

            Console.WriteLine();
            Hack();

This gives us all the details, as we are expecting:


This isn't a nice thing to have - anyone who can somehow gain access to the database can see the passwords. How can we make this better?

Hashing


One way is to hash the passwords. A hash function is something that takes a piece of text and transforms it into another piece of text:


A hash function is one-way in the sense that you can use it to transform "Hello" to "8b1a9953c4611296a827abf8c47804d7", but not the other way around. So if someone gets his hands on the hash of a password, it doesn't mean that he has the password.

Another property of hash functions is that their output changes considerably even with a very small change in the input. Take a look at the following, for instance:



You can see how "8b1a9953c4611296a827abf8c47804d7" is very different from "5d41402abc4b2a76b9719d911017c592". The hashes bear no relationship with each other, even though the passwords are almost identical. This means that a hacker won't be able to notice patterns in the hashes that might allow him to guess one password based on another.

One popular hashing algorithm (though not the most secure) is MD5, which was used to produce the examples above. You can find online tools (such as this one) that allow you to compute an MD5 hash for any string you want.

In order to use MD5 in our code, we'll need to add the following statement near the top of our program code:

using System.Security.Cryptography;

At the beginning of the Program class, we can now create an instance of the MD5 class to use whenever we need:

         private static MD5 hashFunction = MD5.Create();

If you look at the intellisense for MD5, you'll see that it has a ComputeHash() method, which returns an array of byte, rather than a String:


We're going to do some String work, so add the following near the top:

using System.Text;

Let's write a little helper method to hash our passwords, using Strings for both input and output:

        public static String Hash(String input)
        {
            // code goes here
        }

In this method, the first thing we need to do is convert the input String to a byte array, so that ComputeHash() can work with it. This is done using the System.Text.Encoding class, which provides several useful members for converting between Strings and bytes. In our case we can work with the ASCII encoding as follows:

            byte[] inputBytes = Encoding.ASCII.GetBytes(input);

We can then compute the hash itself:

            byte[] hashBytes = hashFunction.ComputeHash(inputBytes);

Since we don't like working with raw bytes, we then convert it to a hexadecimal string:

            StringBuilder sb = new StringBuilder();
            foreach(byte b in hashBytes)
                sb.Append(b.ToString("x2").ToLower());

The "x2" bit converts each byte into two hexadecimal characters. If you think about it for a moment, hexadecimal digits are from 0 to f (representing 0-15 in decimal), which fit into four bits. But each byte is eight bits, so each byte is made up of two hex digits.

Anyway, after that, all we need to do is return the string, so here's the entire code for the method:

        public static String Hash(String input)
        {
            byte[] inputBytes = Encoding.ASCII.GetBytes(input);
            byte[] hashBytes = hashFunction.ComputeHash(inputBytes);
          
            StringBuilder sb = new StringBuilder();
            foreach(byte b in hashBytes)
                sb.Append(b.ToString("x2").ToLower());
          
            return sb.ToString();
        }

We can now change our database to use hashed passwords:

        public static Dictionary<String, String> users = new Dictionary<String, String>()
        {
            { "johnny"Hash("password") },
            { "mary"Hash("flowers") },
            { "chuck"Hash("roundhousekick") },
            { "larry"Hash("password123") }
        };

In this way, we aren't storing the passwords themselves, but their hashes. For example, we're storing "5f4dcc3b5aa765d61d8327deb882cf99" instead of "password". That means we don't store the password itself any more (if you ever signed up to an internet forum or something, and it told you that your password can be reset but not recovered, you now know why). However, we can hash any input password and compare the hashes.

In our Login() method, we now change the line that checks username and password as follows:

             if (users.ContainsKey(username) && users[username] == Hash(password))

Let's try this out (F5):


When the user types "johnny" as the username and "password" as the password, the password is hashed, giving us "5f4dcc3b5aa765d61d8327deb882cf99". Since the passwords were also stored as hashes in our database, it matches. In reality our login is doing the same thing as it was doing before - just that we added a hash step (a) when storing our passwords and (b) when receiving a password as input. Ultimately the password in our database and that entered by the user both end up being hashes, and will match if the actual password was the same.

How does this help us? As you can see from the hack output (last four lines in the screenshot above), someone who manages to breach the database cannot see the passwords; he can only get to the hashes. He can't login using a hash, since that will in turn be hashed, producing a completely different value that won't match the hash in the database.

Although hashing won't make the system 100% secure, it's sure to give any potential hacker a hard time.

Salting


You may have noticed that in the example I used, I had some pretty dumb passwords, such as "password" and "password123". Using a dictionary word such as "flowers" is also not a very good idea. Someone may be able to gain access to one of the accounts by attempting several common passwords such as "password". These attempts can be automated by simple programs, allowing hackers to attempt entire dictionaries of words as passwords in a relatively short period of time.

Likewise, if you know the hash for common passwords (e.g. "5f4dcc3b5aa765d61d8327deb882cf99" is the hash for "password"), it becomes easy to recognise such passwords when you see the expected hash. Hackers can generate dictionaries of hashes for common passwords, known as rainbow tables, and find hashes for common words used as passwords.

We can combat such attacks by a process known as salting. When we compute our hashes, we add some string that we invent. This means changing the first line of our Hash() function as follows:

            byte[] inputBytes = Encoding.ASCII.GetBytes("chuck" + input);

Both the database password and the one entered by the user will be a hash of "chuck" concatenated with the password itself. When the user tries to login, it will still work, but look at what happens now:


The login worked, but the hashes have changed because of the salt! This means that even for a password as common as "password", a hacker cannot identify it from the hash, making rainbow tables much less effective.

Summary


This article described how to store passwords securely. It started off by doing the easiest and worst thing you can do: store them as clear text. A hash function was subsequently introduced, to transform the passwords into text from which the password cannot be retrieved. When a user logs in, the hash of the password he enters is compared with the password hash stored in the database.

Finally, the hashes were salted, by adding an arbitrary piece of text to them, in order to transform the hashes into different values that can't be used to identify common passwords.

I hope this made password security a little easier to understand. Please come back again, and support us by sharing this article with your friends, buying games from GOG.com, or any of the other ways described in the "Support the Ranch" page.

Thursday, May 16, 2013

C# Threading: Bouncing Ball

Hi all! :)

I hope you've enjoyed the articles so far, and found the little ASCII art games both entertaining and mentally stimulating. Towards the end of yesterday's article, C# Basics: Snake Game in ASCII Art (Part 2), we discussed the problems with the Snake game. One of them was that the snake wouldn't move on its own - you had to press a key in order to make the program do something.

In today's article, we're going to begin learning about threads, and use them to overcome this limitation. This time we're going to draw a ball bouncing all over the console window.

Start a new console application, and add the following struct before the class Program:

    struct Vector
    {
        public int X;
        public int Y;
       
        public Vector(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

You'll notice this is exactly the same as the Location struct in C# Basics: Snake Game in ASCII Art (Part 1). Instead of just using it just as a location, we're also going to use it as a direction. You'll see what I mean in a minute. Add the following for starters:

            Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);
            Console.Title = "Bouncing Ball";
           
            Vector ballLocation = new Vector(4012);
            Vector direction = new Vector(-1, -1);

So ballLocation is the location in the console window where we're going to draw our ball. The direction represents where the ball will go next, relative to ballLocation. In this case, the ball starts at (40, 12) and moves in a northwest direction, so the next position will be (39, 11), and then (38, 10), and so on.

[This paragraph is a bit more advanced... feel free to skip it.] The Vector struct is simply a code representation of a mathematical vector, where a vector such as (3, 1) means "three steps to the right, one step down" (depending on what coordinate system you're using). I'm not going to get into the mathematics, but if you're interested, check out my "A Concise Introduction to Vectors" [PDF].

We're now going to add a loop to show the ball and then move it:

            while (true)
            {
                Console.Clear();
                Console.SetCursorPosition(ballLocation.X, ballLocation.Y);
                Console.Write((char4);
               
                ballLocation.X += direction.X;
                ballLocation.Y += direction.Y;
                Thread.Sleep(100);
            }

At the beginning, add the following which is needed by Thread:

using System.Threading;

The code above is an infinite loop; there no condition for which the while loop will end. In this loop, we show an ASCII diamond as our ball, and then simply add the direction to the ballLocation in order to move it. The Thread.Sleep() at the end is simply a delay (in milliseconds) so that you can see the ball move; otherwise it would move quickly. Try changing the value of 100 and use something else (e.g. 1000, which means 1 second) to see what happens.

Press F5 to see the ball move:


You will get an exception once the ball moves off the edge. Add the following to fix this and make the ball change direction when it hits an edge (note || means "OR"):

                if (ballLocation.X == 0 || ballLocation.X == 79)
                    direction.X = -direction.X;
                if (ballLocation.Y == 0 || ballLocation.Y == 24)
                    direction.Y = -direction.Y;

The infinite loop allows the ball to move on its own without user intervention - just as we wanted with Snake. However, there is a problem: we cannot accept any user input like this. In fact, you can only exit by actually closing the window. If you try to add a

Console.ReadKey(true);

at the end of the while loop, we're back to square one: the user must press a key for anything to happen. Clearly, in order to accept input, we need the program to do two things at the same time: let the ball move, and handle user input. Fortunately, such godlike powers are not unique to Chuck Norris and Multiple Man.

A program (or process to be more precise) can do several things at the same time. It can be composed of multiple threads which run at the same time but do different things. This area of programming is called multithreading. Let's see how we can exploit this to allow user input while the ball is moving on its own.

First, move the while loop and the vectors to a new method outside of Main():

        public static void Move()
        {
            Vector ballLocation = new Vector(4012);
            Vector direction = new Vector(-1, -1);
           
            while (true)
            {
                Console.Clear();
                Console.SetCursorPosition(ballLocation.X, ballLocation.Y);
                Console.Write((char4);
               
                ballLocation.X += direction.X;
                ballLocation.Y += direction.Y;
                Thread.Sleep(100);

                if (ballLocation.X == 0 || ballLocation.X == 79)
                    direction.X = -direction.X;
                if (ballLocation.Y == 0 || ballLocation.Y == 24)
                    direction.Y = -direction.Y;
            }
        }

In what remains of the Main() method, add the following code:

            Thread thread = new Thread(Move);
            thread.IsBackground = true;
            thread.Start();
           
            Console.ReadKey(true);

When you press F5 and run the program, you will now end up with two threads:


The new thread is created in the first line of code above. A thread executes the code in a particular method, so we supply the name of the Move() method (without brackets) as a parameter.

In the second line, we set thread.IsBackground = true. A process (running instance of a program) runs as long as there is a foreground thread (such as the main thread) running. Since our new thread is designated as a background thread, the process will terminate once the main thread has exited.

The rest of the Main() method then starts the secondary thread and waits for a keypress. When the keypress is received, Main() ends, and with it the process. If we didn't set the secondary thread as a background thread, the process would keep on running anyway. Try that out. :)

Fantastic. :) In this article, we learned how to use a simple thread in order to allow a program to do two things at the same time. We used this to allow a game to run, while at the same time waiting for user input.

Stay tuned for more! :)

Wednesday, May 15, 2013

C# Basics: Snake Game in ASCII Art (Part 2)

Hi all! :)

In yesterday's article, C# Basics: Snake Game in ASCII Art (Part 1), we created the first part of our Snake Ranch game (a clone of Snake) and learned to use structs. Today we will learn to use lists in order to allow the snake to grow.

At the beginning of yesterday's article, we mentioned that we needed to store each part of the snake in a list, as follows:


The head of the snake would be at (1,1), for example. The remaining parts trail behind it in sequence. We can store these locations in a list, in the following fashion:


There is a List collection in .NET that allows us to do this kind of thing. As with dictionaries (see "C# Basics: Morse Code Converter Using Dictionaries", we first need to include System.Collections.Generic first:

using System.Collections.Generic;

We can now declare a new List of Location objects, and put the head as the first item:

            List<Location> snake = new List<Location>();
            snake.Add(head);

We now change the code that shows the head (from yesterday's article) to show the entire snake in the list:

                // show snake
               
                foreach (Location location in snake)
                {
                    Console.SetCursorPosition(location.X, location.Y);
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write((char178);
                    Console.ResetColor();
                }

All we're doing here is going over each element in the list and showing a portion of the snake there. For now we only have the head though.

Before we make the snake grow, we first need to understand what happens when it moves. Consider this again:


Let's say the head of the snake is at (1,1), and it moves to the left. Then the head becomes (0,1). The tail (last part) of the snake goes away, and all the parts between the new head and the old tail remain unchanged. We need to make some changes to our code to handle this properly. First, before the while loop, we declare a new Location variable called next:

            Location next;

This will hold the position of the new head, based on the keypress received. In the example above, the head is currently at (1,1), but if the user presses the left arrow, then we want next to contain (0,1).

At the beginning of the while loop, we add the following:

                next = snake[0];
               
                Console.Clear();

The first line assigns next to the location of the current head, stored in the first element of the snake variable. Lists can be accessed using [] notation just like arrays.

Next, we change the input handling logic to modify next instead of head:

                switch(keyInfo.Key)
                {
                    case ConsoleKey.Escape:
                        return;
                    case ConsoleKey.UpArrow:
                        if (next.Y > 0)
                            next.Y--;
                        break;
                    case ConsoleKey.DownArrow:
                        if (next.Y < 24)
                            next.Y++;
                        break;
                    case ConsoleKey.LeftArrow:
                        if (next.X > 0)
                            next.X--;
                        break;
                    case ConsoleKey.RightArrow:
                        if (next.X < 79)
                            next.X++;
                        break;
                }

After that, we can do the following:

                snake.Insert(0, next);
                snake.RemoveAt(snake.Count - 1);

Here we are doing exactly what I explained earlier: adding a new head at the beginning of the snake, and removing the old tail. If you press F5 now, you should have functionality just like what we had at the end of yesterday's article (because we still have just one part of the snake):


All we have left to do now is to make the snake get longer when he eats a star. At the beginning, add a new variable to store the location of the star:

Location star = new Location(6020);

After showing the snake, add the following code to show the star:

                // show star
               
                Console.SetCursorPosition(star.X, star.Y);
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.Write('*');
                Console.ResetColor();

Finally, replace the last two lines in the while loop (Insert() and RemoveAt()) with the following logic:

                snake.Insert(0, next);
                if (next.X == star.X && next.Y == star.Y)
                {
                    Random random = new Random();
                    star.X = random.Next(080);
                    star.Y = random.Next(025);
                }
                else
                    snake.RemoveAt(snake.Count - 1);

This code is based on the code from Chase the Star (see "C#: ASCII Art Game (Part 2)"). If the snake bumps into the star, the star moves away to some other random location. Here we are using structs instead of separate starX and starY variables.

The most important thing to understand here is that if the player bumps into the star, we don't remove the snake's tail, thus allowing it to grow. We can now test it:



Awesome! :) We have just made our own variant of Snake using ASCII art. If you test it thoroughly, you'll notice there are a few problems:

  1. The snake doesn't move on its own as time goes by. You need to press an arrow key for it to move.
  2. The snake can bump into itself or the edges and nothing bad happens.
  3. If the snake moves into the edge, it sort of compresses. When you move away, it regains its former length.
  4. The star can appear over the snake.
  5. No obstacles... boring!

As you can see, it can be quite complicated to make a complete game, as there are many things you need to take care of. Making a fully blown Snake game would take many more articles, so I'll leave it at that. In this article we use generic lists to implement the Snake concept. If you're really adventurous, you might want to try and fixing some of the issues above as an exercise. Don't worry if you don't manage - just thinking about strategies to solve them will teach you how to think like a programmer.

I hope you enjoyed this, and come back for more programming articles! :)

Here is the full code for Snake Ranch:

using System;
using System.Collections.Generic;

namespace CsSnake
{
    struct Location
    {
        public int X;
        public int Y;
       
        public Location(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    };
   
    class Program
    {
        public static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);
            Console.Title = "Snake Ranch";
           
            Location head = new Location(4012);
            List<Location> snake = new List<Location>();
            snake.Add(head);
           
            Location next;

            Location star = new Location(6020);
           
            while (true)
            {
                next = snake[0];
               
                Console.Clear();
               
                // show snake
               
                foreach (Location location in snake)
                {
                    Console.SetCursorPosition(location.X, location.Y);
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write((char178);
                    Console.ResetColor();
                }
               
                // show star
               
                Console.SetCursorPosition(star.X, star.Y);
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.Write('*');
                Console.ResetColor();
               
                // handle input
               
                ConsoleKeyInfo keyInfo = Console.ReadKey(true);
               
                switch(keyInfo.Key)
                {
                    case ConsoleKey.Escape:
                        return;
                    case ConsoleKey.UpArrow:
                        if (next.Y > 0)
                            next.Y--;
                        break;
                    case ConsoleKey.DownArrow:
                        if (next.Y < 24)
                            next.Y++;
                        break;
                    case ConsoleKey.LeftArrow:
                        if (next.X > 0)
                            next.X--;
                        break;
                    case ConsoleKey.RightArrow:
                        if (next.X < 79)
                            next.X++;
                        break;
                }
               
                snake.Insert(0, next);
                if (next.X == star.X && next.Y == star.Y)
                {
                    Random random = new Random();
                    star.X = random.Next(080);
                    star.Y = random.Next(025);
                }
                else
                    snake.RemoveAt(snake.Count - 1);
            }
        }
    }
}

C# Basics: Snake Game in ASCII Art (Part 1)

Hi! :)

In recent articles, we created a game called Chase the Star (see "C#: ASCII Art Game (Part 1)" and "C#: ASCII Art Game (Part 2)"), and also learned about what The ASCII Table (C#) has to offer to us.

In today's article we're going to create a little game like the classic Snake. The first Snake game I ever played was probably Nibbles, on an ancient DOS machine. Rumour has it that in the Stone Age, when cavemen used to dance around a bonfire and chant "Ugh!", this machine was used to make a series of electronic beeps in a disco fashion. Each caveman would then walk like an Egyptian.

OK, we're going to start with something quite similar to Chase the Star. The difference is that our snake will get longer when it eats the star. Instead of storing just the location of our player, as with Chase the Star, we are going to need a whole list of locations:


Start a new console application. Since we're going to have a lot of locations, it makes sense to define a structure or struct storing X and Y, rather than keeping separate variables for them. This must be declared at the same level as class Program (ideally just before it):

    struct Location
    {
        int X;
        int Y;
    };

In Main(), we can now store the location of the head of the snake as follows:

            Location head;
            head.X = 40;
            head.Y = 12;

If you try compiling now, you'll get the following error:

'CsSnake.Location.X' is inaccessible due to its protection level (CS0122)

In order to make this work, you need to set the Location's members to public:

    struct Location
    {
        public int X;
        public int Y;
    };

Even better, instead of setting X and Y separately, we can define a constructor:

    struct Location
    {
        public int X;
        public int Y;
      
        public Location(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    };

In Main(), we can now declare head in one line as follows:

Location head = new Location(4012);

A constructor, in this case Location(int x, int y), is a method that always has the same name as the struct or class it is in (more about classes another time). It can be used to pass parameters that will be used when the object is created. In many constructors, including this one, those parameters are used to set the member variables in the struct (in this case X and Y).

In this case, we declare a new Location called head and pass 40 and 12 as parameters. Those end up in the constructor, where they are assigned to the X and Y variables within head. The this keyword simply states that we are working with the member variables of head (which is a Location).

We can now add the following at the beginning of Main():

            Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);
            Console.Title = "Snake Ranch";

...and some logic to show the head of the snake and handle movement:

            while (true)
            {
                // show head
              
                Console.Clear();
                Console.SetCursorPosition(head.X, head.Y);
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write((char178);
                Console.ResetColor();
              
                // handle input
              
                ConsoleKeyInfo keyInfo = Console.ReadKey(true);
              
                switch(keyInfo.Key)
                {
                    case ConsoleKey.Escape:
                        return;
                    case ConsoleKey.UpArrow:
                        if (head.Y > 0)
                            head.Y--;
                        break;
                    case ConsoleKey.DownArrow:
                        if (head.Y < 24)
                            head.Y++;
                        break;
                    case ConsoleKey.LeftArrow:
                        if (head.X > 0)
                            head.X--;
                        break;
                    case ConsoleKey.RightArrow:
                        if (head.X < 79)
                            head.X++;
                        break;
                }
            }

We now have something similar to Chase the Star, except that we don't yet have the star functionality:


We are using character number 178 from the ASCII Table to represent the head of the snake. When the user presses an arrow key, we modify the X or Y members of head. We can access them as head.X or head.Y.

Wonderful :) In this article we implemented the first part of our Snake game, and learned to use structs. Tomorrow we will learn to use Lists, which we will need to store each part of the snake. This will allow us to complete the game. :)

Check back tomorrow for more! :)

Saturday, May 11, 2013

The ASCII Table (C#)

Hi! :)

In previous articles, we have seen how to create a simple game based within the console window (Part 1Part 2). In this article we're going to find out what ASCII is about, and how we can draw some basic shapes  using the characters available in the console. Don't mind the length of this article... there's a really long chunk of code that you can just copy and paste. Read on! :)

So far we have displayed strings in the console window many times. However, a computer does not know anything about text; it can only work with numbers. So when you do something like this:

             Console.WriteLine("Hello world!");

...each character maps to a particular number (e.g. the 'H' is 72, the 'e' is 101, and so on). ASCII is a standard defining a set of basic characters such as these. Check out an ASCII Table to see how the characters are organised.

The standard ASCII is a set of 128 characters, the first 32 and last 1 of which are control characters such as the Carriage Return (13) and Line Feed (10), which together make a newline. The remaining characters are the text characters that we are used to.

There is also an extended set of another 128 ASCII characters. These consist of some non-English characters as well as some line and block characters that can be used to draw something like the screenshot towards the beginning of my article "C#: ASCII Art Game (Part 1)".

We can write all the 256 ASCII characters to the console window using a simple loop. Start a new SharpDevelop project, and use the following code:

            int i = 0;
            while (i < 256)
            {
                Console.Write(Convert.ToChar(i));
                i++;
            }

All we do is run this loop from 0 to 255 and write the corresponding ASCII character. We use the Convert class that is familiar from my article "C# Basics: Fun with Integers", but this time we convert from an integer to a character.

This is easy, but there's a better way to do this. Replace the above code with this:

            for (int i = 0; i < 255; i++)
            {
                Console.Write((char) i);
            }

This for loop does the same as above, but is much more compact. Initialising i, incrementing it, and the loop condition are all contained within the brackets of the for statement. The braces contain the statements to carry out with each iteration. If you have just one statement, as in this case, you may omit the curly brackets.

Also, you'll notice that I changed how we convert between integer and character. This method is called type casting - you just put the desired type (char in this case) beside the variable to be converted. The end result is still the same as with using Convert.ToChar().

When you run this code (F5), you'll hear a beep and see this:


Some things will seem weird here. There are what appear to be smiley faces, an uncalled-for newline, a whole bunch of question marks, and lots of strange characters after that, not to mention the beep.

The smiley faces, newline and beep are all due to the control characters at the beginning of the ASCII set. The beep is due to the bell character (7); the newline is due to the line feed character (10). The smiley faces and other crap at the beginning are just the character representations of those control characters. Additionally, what you're not seeing is that the carriage return (13) is moving the cursor position to the beginning of the line, so characters 11 and 12 are being overwritten. Let's rectify this:

            for (int i = 0; i < 255; i++)
            {
                if (i == 13)
                    Console.Write(' ');
                else
                    Console.Write((char) i);
            }

As for the extended character codes not matching the ASCII Table, that's due to some encoding mumbo-jumbo that I'm not going to get into, but the solution is pretty simple: just add the following line before the for loop:

            Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);

The result is now different:


That's better! Now, we can use those extended ASCII characters to draw something. This is called ASCII art. Here's some full code:

            Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);
        
            for (int i = 0; i < 255; i++)
            {
                if (i == 13)
                    Console.Write(' ');
                else
                    Console.Write((char) i);
            }

            // top-left corner
        
            Console.SetCursorPosition(3010);
            Console.Write((char201);
        
            // top-right corner
        
            Console.SetCursorPosition(5310);
            Console.Write((char187);
        
            // mid-left T-junction
        
            Console.SetCursorPosition(3013);
            Console.Write((char204);
        
            // mid-right T-junction
        
            Console.SetCursorPosition(5313);
            Console.Write((char185);
        
            // bottom-left corner
        
            Console.SetCursorPosition(3015);
            Console.Write((char200);
        
            // bottom-right corner
        
            Console.SetCursorPosition(5315);
            Console.Write((char188);
        
            // horizontal edges
        
            for (int i = 31; i < 53; i++)
            {
                Console.SetCursorPosition(i, 10);
                Console.Write((char205);
                Console.SetCursorPosition(i, 13);
                Console.Write((char205);
                Console.SetCursorPosition(i, 15);
                Console.Write((char205);
            }
        
            // vertical edges
        
            Console.SetCursorPosition(3011);
            Console.Write((char186);
            Console.SetCursorPosition(3012);
            Console.Write((char186);
            Console.SetCursorPosition(3014);
            Console.Write((char186);
            Console.SetCursorPosition(5311);
            Console.Write((char186);
            Console.SetCursorPosition(5312);
            Console.Write((char186);
            Console.SetCursorPosition(5314);
            Console.Write((char186);
        
            // text
        
            Console.SetCursorPosition(3211);
            Console.Write("     Welcome to");
            Console.SetCursorPosition(3212);
            Console.Write(" Programmer's Ranch");
            Console.SetCursorPosition(3214);
            Console.Write("by Daniel D'Agostino");
        
            Console.SetCursorPosition(024);

            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);

...and the output:


Right... although we have achieved our goal, you'll notice two things here that feel a little uncomfortable. First, the code is rather long. For this kind of thing, the drawing data is best kept in files. Secondly, there is quite a bit of repetition: lots of Console.SetCursorPosition() calls followed by Console.Write() calls. This may be alleviated by using methods, but more on that in another article.

Great! In this article we learned about what the ASCII table has to offer us. It doesn't sound like much, but if you're creative, you can use it to make some really cool games. Also, ASCII is probably the most basic character encoding there is; if you do advanced programming using text later on, knowing ASCII is a useful foundation.

I have more good things coming up in the next few articles, so don't go away! :)

Optional exercises:

  1. Replace the 'X' representing the player in our ASCII art game (Part 1Part 2) with a smiley face from the ASCII character set.
  2. Draw a top-down view of a house in the console window using ASCII art. Use '-' for doors and '+' for windows.
  3. If you feel like going overboard, draw something complex (such as an elaborate logo design or an overworld map) using ASCII art and send me a screenshot. I'll post the best ones here.