One of the projects provided as demos for my class at the Telerik Academy was a console implementation of the classic Snake game (they named it JustSnake). You can see it and some of its code on the screen recording of my lecture "Console Input and Output", which I will share here very soon.
It inspired me to build my own little demo console game. I chose yet another classic game - the originally Russian Tetris which I named TeleTris. It took one evening of coding and debugging and I must say I am quite satisfied with the result.
Article level: Reasonably moderate
TeleTris In Action
Of course I'm attaching the full source code solution (and pre-built executable) here for anyone who wishes to download and play. Note that in order to run the executable, you will need to have the Microsoft .NET Framework (4.0) installed on your machine.
Everyone is free to suggest improvements and bug fixes. I am aware of some minor graphic bugs and of the fact that the game's responsiveness could be improved, but for a single evening of work I think it's ok.
Here's a small screen capture of TeleTris in action. Click to open the animated version:
Code Overview
The code consists of a straight-forward console application project, split it into 4 files:
-
Program.cs
This is the default main file. It contains the code for the fancy splash screen (which is also used as a credits screen) and all it does is trigger the main menu, which takes the functionality on from there. -
MainMenu.cs
This file contains the functionality of the main options menu and of the game-speed setting menu. These 2 menus function in a similar way: On every change, the menu is reprinted with the newly selected option highlighted. Of course, the main menu invokes all other functions: the actual game, speed setting, credits screen and quitting the application. -
TetrisShape.cs
This file contains the base abstract class TetrisShape, and a few sample derived classes: Shape1, Shape2, Shape3 and Shape4. The shapes defer from one another only in their outlines, which are stored in a bidimensional array of characters.
The functionality implemented in the TetrisShape class covers the ability to rotate the shape clockwise, detect the utilized shape boundaries within the array (recalculated when the shape is constructed and when the shape is rotated) and the option to print out the shape to the console at specific coordinates. If the shape has already been displayed (determined by the 2 members lastPositionX and lastPositionY), it is first removed from its previous location, then printed in the new one.
A random colour, out of a limited choice of console colours, is picked in the constructor of the base class for every new shape (yes, I know that in the classic Tetris game each shape has its own set colour. However this was an administrative decision and once it got voted for unanimously by me, I could not object to it anymore).
The TetrisShape class has also a static method, GetShape, which is kinda like a factory for retrieving a random shape out of the 4 possible shapes. -
Game.cs
Naturally the most complex of the 4 files as it contains the Play method which controls the entire game flow.
It uses a member bidimensional array named SkyLine, which reflects the screen area with all the shapes which have already fallen (and stopped falling). This is due to the fact that reading the console screen buffer with C# is not a trivial task at all, and the game needs to be aware of what's going on on the client's screen: to know when shapes collide, when rows are complete and how to reprint the skyline after complete rows are deleted.
In a while loop which iterates as long as it can, a new shape is created and starts falling (reprinted to the console on every step, considering the user's keystrokes of left/right/down arrows, spacebar and Esc). Once a shape detects a collision directly underneath it (with the help of the SkyLine), it stops falling and a new shape is retrieved. If the user clicks the down arrow, the shape starts falling faster, while ignoring the user's keys until it reaches its lowest point.
Before a new shape is retrieved, the SkyLine is updated, and checked for complete rows. If such is found, it is: (1) coloured in yellow, (2) deleted from the SkyLine, while the entire SkyLine array shifts downwards, (3) the updated part of the SkyLine is reprinted to the screen (in gray only. Sorry, that was another administrative decision of laziness) (4) the score is updated and displayed.
As written above, you are welcome to download, explore and fix my bugs, because I am definitely not planning to do so for this project :-)