In previous articles, we have seen how to create a simple game based within the console window (Part 1, Part 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++;
}
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);
}
{
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().
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().
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);
}
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(30, 10);
Console.Write((char) 201);
// top-right corner
Console.SetCursorPosition(53, 10);
Console.Write((char) 187);
// mid-left T-junction
Console.SetCursorPosition(30, 13);
Console.Write((char) 204);
// mid-right T-junction
Console.SetCursorPosition(53, 13);
Console.Write((char) 185);
// bottom-left corner
Console.SetCursorPosition(30, 15);
Console.Write((char) 200);
// bottom-right corner
Console.SetCursorPosition(53, 15);
Console.Write((char) 188);
// horizontal edges
for (int i = 31; i < 53; i++)
{
Console.SetCursorPosition(i, 10);
Console.Write((char) 205);
Console.SetCursorPosition(i, 13);
Console.Write((char) 205);
Console.SetCursorPosition(i, 15);
Console.Write((char) 205);
}
// vertical edges
Console.SetCursorPosition(30, 11);
Console.Write((char) 186);
Console.SetCursorPosition(30, 12);
Console.Write((char) 186);
Console.SetCursorPosition(30, 14);
Console.Write((char) 186);
Console.SetCursorPosition(53, 11);
Console.Write((char) 186);
Console.SetCursorPosition(53, 12);
Console.Write((char) 186);
Console.SetCursorPosition(53, 14);
Console.Write((char) 186);
// text
Console.SetCursorPosition(32, 11);
Console.Write(" Welcome to");
Console.SetCursorPosition(32, 12);
Console.Write(" Programmer's Ranch");
Console.SetCursorPosition(32, 14);
Console.Write("by Daniel D'Agostino");
Console.SetCursorPosition(0, 24);
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:
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(30, 10);
Console.Write((char) 201);
// top-right corner
Console.SetCursorPosition(53, 10);
Console.Write((char) 187);
// mid-left T-junction
Console.SetCursorPosition(30, 13);
Console.Write((char) 204);
// mid-right T-junction
Console.SetCursorPosition(53, 13);
Console.Write((char) 185);
// bottom-left corner
Console.SetCursorPosition(30, 15);
Console.Write((char) 200);
// bottom-right corner
Console.SetCursorPosition(53, 15);
Console.Write((char) 188);
// horizontal edges
for (int i = 31; i < 53; i++)
{
Console.SetCursorPosition(i, 10);
Console.Write((char) 205);
Console.SetCursorPosition(i, 13);
Console.Write((char) 205);
Console.SetCursorPosition(i, 15);
Console.Write((char) 205);
}
// vertical edges
Console.SetCursorPosition(30, 11);
Console.Write((char) 186);
Console.SetCursorPosition(30, 12);
Console.Write((char) 186);
Console.SetCursorPosition(30, 14);
Console.Write((char) 186);
Console.SetCursorPosition(53, 11);
Console.Write((char) 186);
Console.SetCursorPosition(53, 12);
Console.Write((char) 186);
Console.SetCursorPosition(53, 14);
Console.Write((char) 186);
// text
Console.SetCursorPosition(32, 11);
Console.Write(" Welcome to");
Console.SetCursorPosition(32, 12);
Console.Write(" Programmer's Ranch");
Console.SetCursorPosition(32, 14);
Console.Write("by Daniel D'Agostino");
Console.SetCursorPosition(0, 24);
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:
- Replace the 'X' representing the player in our ASCII art game (Part 1, Part 2) with a smiley face from the ASCII character set.
- Draw a top-down view of a house in the console window using ASCII art. Use '-' for doors and '+' for windows.
- 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.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.