Gigi Labs

Please follow Gigi Labs for the latest articles.

Sunday, March 30, 2014

SDL2: Animations with Sprite Sheets

Hi people! :)

[Update 2015-11-14: This article is out of date. Check out the latest version at Gigi Labs.]

We've worked with images in several of the SDL2 tutorials published so far. In today's article, we're going to use a very simple technique to animate our images and make them feel more alive.

Before we start, we first need to set up a new project as follows:

  1. Follow the steps in "SDL2: Setting up SDL2 in Visual Studio (2013 or any other)" to set up an SDL2 project.
  2. Follow the steps at the beginning of "SDL2: Loading Images with SDL_image" to use SDL_image in your project.
  3. Configure your project's working directory as described in "SDL2: Displaying text with SDL_ttf", i.e. in your project's Properties -> Configuration Properties -> Debugging, set Working Directory to $(SolutionDir)$(Configuration)\ .
  4. Start off with the following code, adapted from "SDL2: Loading Images with SDL_image":
#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Sprite Sheets",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
        480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("spritesheet.png");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
        case SDL_QUIT:
            quit = true;
            break;
        }

        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}


Before we do anything, we need a sprite sheet. A sprite sheet is really just a cartoon. Like this:


This image is 128 pixels wide and 64 pixels high. It consists of 4 sub-images (called sprites or frames), each 32 pixels wide. If we can rapidly render each image in quick succession, just like a cartoon, then we have an animation! :D

Now, those ugly borders in the image above are just for demonstration purposes. Here's the same image, without borders and with transparency:


If we now try to draw the above on the default black background, we're not going to see anything, are we? Fortunately, it's easy to change the background colour, and we've done it before in "SDL2: Keyboard and Mouse Movement (Events)". Just add the following two lines before the while loop:

    SDL_SetRenderDrawColor(renderer, 168, 230, 255, 255);
    SDL_RenderClear(renderer);


Now we get an early peek at what the output is going to look like. Press Ctrl+Shift+B to build the project, and then copy SDL2.dll, all the SDL_image DLLs, and the spritesheet into the Debug folder where the executable is generated.

Once that is done, hit F5:


So at this point, there are two issues we want to address. First, we don't want our image to take up the whole window, as it's doing above. Secondly, we only want to draw one sprite at a time. Both of these are pretty easy to solve if you remember SDL_RenderCopy()'s last two parameters: a source rectangle (to draw only a portion of the image) and a destination rectangle (to draw the image only to a portion of the screen).

So let's add the following at the beginning of the while loop:

        SDL_Rect srcrect = { 0, 0, 32, 64 };
        SDL_Rect dstrect = { 10, 10, 32, 64 };


...and then update our SDL_RenderCopy() call as follows:

        SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);


Note that the syntax we're using to initialise our SDL_Rects is just shorthand to set all of the x, y, w (width) and h (height) members all at once.

Let's run the program again and see what it looks like:


Okay, so like this we are just rendering the first sprite to a part of the window. Now, let's work on actually animating this. At the beginning of the while loop, add the following:

        Uint32 ticks = SDL_GetTicks();


SDL_GetTicks() gives us the number of milliseconds that passed since the program started. Thanks to this, we can use the current time when calculating which sprite to use. We can then simply divide by 1000 to convert milliseconds to seconds:

        Uint32 seconds = ticks / 1000;


We then divide the seconds by the number of sprites in our spritesheet, in this case 4. Using the modulus operator ensures that the sprite number wraps around, so it is never greater than 3 (remember that counting is always zero-based, so our sprites are numbered 0 to 3).

        Uint32 sprite = seconds % 4;


Finally, we replace our srcrect declaration by the following:

        SDL_Rect srcrect = { sprite * 32, 0, 32, 64 };


Instead of using an x value of zero, as we did before, we're passing in the sprite value (between 0 and 3, based on the current time) multiplied by 32 (the width of a single sprite). So with each second that passes, the sprite will be extracted from the image at x=0, then x=32, then x=64, then x=96, back to x=0, and so on.

Let's run this again:


You'll notice two problems at this stage. First, the animation is very irregular, in fact it doesn't animate at all unless you move the mouse or something. Second, the sprites seem to be dumped onto one another, as shown by the messy image above.

Fortunately, both of these problems can be solved with code we've already used in "SDL2: Keyboard and Mouse Movement (Events)". The first issue is because we're using SDL_WaitEvent(), so the program doesn't do anything unless some event occurs. Thus, we need to replace our call to SDL_WaitEvent() with a call to SDL_PollEvent():

        SDL_PollEvent(&event);


The second problem is because we are drawing sprites without clearing the ones we drew before. All we need to do is add a call to SDL_RenderClear() before we call SDL_RenderCopy():

        SDL_RenderClear(renderer);


Great! You can now admire our little character shuffling at one frame per second:


It's good, but it's a bit slow. We can make it faster by replacing the animation code before the srcrect declaration with the following (10 frames per second):

        Uint32 ticks = SDL_GetTicks();
        Uint32 sprite = (ticks / 100) % 4;


Woohoo! :D Look at that little guy dance!

So in this article, we learned how to animate simple characters using sprite sheets, which are really just a digital version of a cartoon. We used SDL_RenderCopy()'s srcrect parameter to draw just a single sprite from the sheet at a time, and selected that sprite using the current time based on SDL_GetTicks(). The full code is below.

Thanks for reading! Stay tuned for more articles. :)

#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Sprite Sheets",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
        480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("spritesheet.png");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

    SDL_SetRenderDrawColor(renderer, 168, 230, 255, 255);
    SDL_RenderClear(renderer);

    while (!quit)
    {
        Uint32 ticks = SDL_GetTicks();
        Uint32 sprite = (ticks / 100) % 4;
        SDL_Rect srcrect = { sprite * 32, 0, 32, 64 };
        SDL_Rect dstrect = { 10, 10, 32, 64 };

        SDL_PollEvent(&event);

        switch (event.type)
        {
        case SDL_QUIT:
            quit = true;
            break;
        }

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}

Saturday, March 29, 2014

SDL2: Displaying text with SDL_ttf

Hello again! :)

[Update 2015-11-14: This article is out of date. Check out the latest version at Gigi Labs.]

In this article, we're going to learn how we can write text in our window. To do this, we'll use the SDL_ttf library.

First, we need to set up a project to work with SDL2. To do this, follow the instructions in my earlier article, "SDL2: Setting up SDL2 in Visual Studio (2013 or any other)".

Next, we need to actually download and use the SDL_ttf library. This is very similar to what we did with SDL_image in "SDL2: Loading Images with SDL_image". First, download the Visual C++ Development Libraries from the SDL_ttf 2.0 homepage:


From the archive you just downloaded, you need to do the same as in "SDL2: Loading Images with SDL_image" to:

  1. Copy SDL_ttf.h to the include folder where your other SDL2 files reside.
  2. Copy SDL2_ttf.lib to the lib\x86 folder where your other SDL2 files reside.
  3. After compiling your project (as it is, without using SDL_ttf just yet), copy the DLL files from the lib\x86 folder, as well as the regular SDL2.dll, to the Debug folder where your project's executable is created.

Then, in your project's properties, go to Linker -> Input and add the following: SDL2_ttf.lib in the Additional Dependencies field. This field should now contain the following:

SDL2.lib; SDL2main.lib; SDL2_ttf.lib

Good. Now, let's start with the following code which is a modified version of the code from about halfway through "SDL2: Displaying an Image in the Window":

#include <SDL.h>

int main(int argc, char ** argv)
{
 bool quit = false;
 SDL_Event event;

 SDL_Init(SDL_INIT_VIDEO);

 SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",
  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
  480, 0);
 SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

 while (!quit)
 {
  SDL_WaitEvent(&event);

  switch (event.type)
  {
  case SDL_QUIT:
   quit = true;
   break;
  }
 }

 SDL_DestroyRenderer(renderer);
 SDL_DestroyWindow(window);
 SDL_Quit();

 return 0;
}

The first thing we need to do in order to use SDL_ttf is include the relevant header file:

#include <SDL_ttf.h>

Then, we initialise the SDL_ttf library right after we call SDL_Init():

 TTF_Init();

...and we clean it up just before we call SDL_Quit():

 TTF_Quit();

Right after we initialise our renderer, we can now load a font into memory:

 TTF_Font * font = TTF_OpenFont("arial.ttf", 25);

TTF_OpenFont() takes two parameters. The first is the path to the TrueType Font (TTF) that it needs to load. The second is the font size (in points, not pixels). In this case we're loading Arial with a size of 25.

A font is a resource like any other, so we need to free the resources it uses near the end:

 TTF_CloseFont(font);

We can now render some text to an SDL_Surface using TTF_RenderText_Solid(). which takes the font we just created, a string to render, and an SDL_Color which we are passing in as white in this case:

 SDL_Color color = { 255, 255, 255 };
 SDL_Surface * surface = TTF_RenderText_Solid(font,
  "Welcome to Programmer's Ranch", color);

We can then create a texture from this surface as we did in "SDL2: Displaying an Image in the Window":

 SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
  surface);

And yet again, we should not forget to release the resources we just allocated near the end, so let's do that right away:

 SDL_DestroyTexture(texture);
 SDL_FreeSurface(surface);

Now all we need is to actually render the texture. We've done this before; just add the following just before the end of your while loop:

  SDL_RenderCopy(renderer, texture, NULL, NULL);
  SDL_RenderPresent(renderer);

Okay, now before we actually run this program, we need to put our Arial TTF font somewhere where our program can find it. Go to C:\Windows\Fonts, and fron there copy the Arial font into the Debug folder where your executable is compiled. This will result in several TTF files, although we're only going to use arial.ttf.

Now if you've read my SDL_image tutorials before, you'll know that the program runs from a different directory when running from Visual Studio and when running directly from the executable - in fact if you run the program now from Visual Studio, it will crash; but if you run the executable directly it will work fine. Rather than replicating our TTF file across folders to satisfy both scenarios, here's a little trick to make it work without further ado.

Go into your project properties, and then under Configuration Properties -> Debugging, there's a field called Working Directory. Change this from $(ProjectDir) (the default setting) to $(SolutionDir)$(Configuration)\ :


Great, now let's admire the fruit of our work:


Nooooooooooooooo! This isn't quite what we were expecting, right? This is happening because the texture is being stretched to fill the contents of the window. The solution is to supply the dimensions occupied by the text in the dstrect parameter of SDL_RenderCopy() (as we did in "SDL2: Displaying an Image in the Window"). But how can we know these dimensions?

If you check out Will Usher's SDL_ttf tutorial, you'll realise that a function called SDL_QueryTexture() can give you exactly this information (and more). So before our while loop, let's add the following code:

 int texW = 0;
 int texH = 0;
 SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
 SDL_Rect dstrect = { 0, 0, texW, texH };

Finally, we can pass dstrect in our call to SDL_RenderCopy():

  SDL_RenderCopy(renderer, texture, NULL, &dstrect);

Let's run the program now:


Much better! :)

In this article, we learned how to use the SDL_ttf to render text using TTF fonts in SDL2. Using the SDL_ttf library in a project was just the same as with SDL_image. To actually use fonts, we first rendered text to a surface, then passed it to a texture, and finally to the GPU. We used SDL_QueryTexture() to obtain the dimensions of the texture, so that we could render the text in exactly as much space as it needed. We also learned how we can set up our project to use the same path regardless of whether we're running from Visual Studio or directly from the executable.

Below is the full code for this article. Come back again for more! :)

#include <SDL.h>
#include <SDL_ttf.h>

int main(int argc, char ** argv)
{
 bool quit = false;
 SDL_Event event;

 SDL_Init(SDL_INIT_VIDEO);
 TTF_Init();

 SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",
  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
  480, 0);
 SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

 TTF_Font * font = TTF_OpenFont("arial.ttf", 25);
 const char * error = TTF_GetError();
 SDL_Color color = { 255, 255, 255 };
 SDL_Surface * surface = TTF_RenderText_Solid(font,
  "Welcome to Programmer's Ranch", color);
 SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
  surface);

 int texW = 0;
 int texH = 0;
 SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
 SDL_Rect dstrect = { 0, 0, texW, texH };

 while (!quit)
 {
  SDL_WaitEvent(&event);

  switch (event.type)
  {
  case SDL_QUIT:
   quit = true;
   break;
  }

  SDL_RenderCopy(renderer, texture, NULL, &dstrect);
  SDL_RenderPresent(renderer);
 }

 SDL_DestroyTexture(texture);
 SDL_FreeSurface(surface);
 TTF_CloseFont(font);

 SDL_DestroyRenderer(renderer);
 SDL_DestroyWindow(window);
 TTF_Quit();
 SDL_Quit();

 return 0;
}

Sunday, March 23, 2014

C# AppSettings: Saving User Preferences in a WPF Browser application

Hey Ya! :)

In yesterday's article, "C# AppSettings: Launching Programs and Storing AppSettings", we learned how you can store application settings in an App.config file so that they can be easily changed without having to recompile the program. This is useful for settings that don't change very often, but is not the best way to store user preferences.

In today's article, we will see how we can use a .NET Settings file in order to save user preferences. To do this, we will build a simple WPF browser application* and allow the user to save his homepage.

* For those who already know a little bit about WPF, we're just going to make a simple application that includes a WebBrowser control - not an XBAP.

So, for starters, create a new WPF application using your favourite IDE. Aside from an App.xaml, you should also have a window - this would be Window1.xaml in SharpDevelop, or MainWindow.xaml in Visual Studio.

Change the window's TitleWidth and Height properties to something decent (e.g. width of 800 and height of 600). Then, replace the default <Grid> in the window's XAML with the following:

    <DockPanel>
        <DockPanel LastChildFill="True" DockPanel.Dock="Top">
            <Button Name="GoButton" DockPanel.Dock="Right" Margin="5 5 5 5" Click="Button_Click">Go</Button>
            <Button Name="SaveButton" DockPanel.Dock="Right" Margin="5 5 5 5">Save homepage</Button>
            <TextBox Name="Homepage" DockPanel.Dock="Left" Margin="5 5 5 5" />
        </DockPanel>
        <WebBrowser Name="Browser" VerticalAlignment="Stretch" />
    </DockPanel>

This isn't a WPF tutorial so don't worry about the above XAML; you'll see what it does in a second. Find the window's codebehind file by expanding your Window1.xaml (or MainWindow.xaml) node in Solution Explorer, and open it:


In the window class's constructor, add the following code after InitializeComponent():

            string homePageUrl = "http://en.wikipedia.org/wiki/Main_Page";
            this.Homepage.Text = homePageUrl;
            this.Browser.Navigate(homePageUrl);

You can now run the application to see what it looks like:


That was pretty easy! We set up the browser embedded in our window to load Wikipedia by default, and that's what it did. Now, let's get our program to actually do something.

In the XAML for the "Go" button, start typing the word "Click", then press TAB twice. This should generate the following code in your window's codebehind file (remember, it's the .xaml.cs file):

        void GoButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

Replace the body of this method with the following:

            this.Browser.Navigate(this.Homepage.Text);

We can now type in a URL and press the "Go" button to navigate there:


Now, let's work on that "Save homepage" button. First, add a button handler as you did before - by starting to type the word "Click" in the XAML for the "Save homepage" button, pressing TAB, selecting "<new event handler>", and then pressing TAB again. You should have an empty handler similar to the one you had for the "Go" button earlier:

        void SaveButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

Next, right click on your project in Solution Explorer, and select Add -> New Item... and add a new Settings file. If you're using SharpDevelop, you'll find this under the Misc category:


This file opens up a table where you can add settings as you like. Let's add one for the homepage:


You just need to set the name, data type, and default value of the property. The Scope can be either User or Application. This article at MSDN explains the difference:
Application-scope settings are read only, and can only be changed at design time or by altering the <AssemblyName>.exe.config file in between application sessions. User-scope settings, however, can be written at run time, just as you would change any property value. The new value persists for the duration of the application session. You can persist changes to user settings between application sessions by calling the Settings.Save method. These settings are saved in the User.config file.
In short, Application-scope settings are pretty similar to what we did yesterday in "C# AppSettings: Launching Programs and Storing AppSettings", while User-scope settings are ideal for saving user preferences - which is what we want to do now.

In your window's constructor, you can now load the homepage from your settings. You first need to build your project to allow the IDE to do some magic underneath (otherwise you won't be able to find the property. Then, you can load the homepage setting like this:

            string homePageUrl = Settings1.Default.HomePage;

The good thing about these kinds of settings are that they are strongly-typed. This means that if you're loading, for example, an integer, you can just assign it directly to an integer variable without further ado. Using regular AppSettings (see "C# AppSettings: Launching Programs and Storing AppSettings"), on the other hand, you first have to read values into strings and then convert them to the appropriate type.

Saving settings is also pretty straightforward. You assign them using the same notation as above, and then Save() them so that the settings can be remembered next time you run the application:

        void SaveButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Settings1.Default.HomePage = this.Homepage.Text;
            Settings1.Default.Save();
           
            MessageBox.Show("Settings have been saved", "Homepage update");
        }

So now, we can run our application, enter a new URL in the homepage, and click the "Save homepage" button:


...and the next time we run our application, it loads our new homepage by default:


As you can see, the WPF WebBrowser control is actually some version of Internet Explorer - you can see it compared to a REAL browser in a previous screenshot. Still, Internet Explorer can sometimes be useful. To download another browser, for instance. :D

Cool. :) In this article, we saw how to use a .NET Settings file to load and save user preferences quickly and easily. We saw this in action by loading and saving the homepage in a simple WPF browser application. Thanks for reading, and see you in time for the next article! :)

Saturday, March 22, 2014

C# AppSettings: Launching Programs and Storing AppSettings

Hi all! :)

Today we're going to write a little program that can start other programs. For example, it might launch MS Word, or your favourite browser. From this we will learn how to actually start other programs using C#, and also how to add settings into an application configuration file so that they can easily be changed.

Start off by creating a new Console Application using your favourite IDE. Throw out any code already in Main(), and add this initial code:

            Console.Title = "Launcher";
          
            // TODO code goes here
          
            Console.ReadLine();

Now, to start a program from our code, we need to use the Process class. To be able to use it, we need to add the following to our usings:

using System.Diagnostics;

Starting a program is really easy. All we need to do is replace our "TODO" comment with the following:

            string filePath = @"C:\tools\notepad++\notepad++.exe";
            Process.Start(filePath);

And sure enough, when we run our program, Notepad++ is opened as well:


Let us now take this a step further. We can allow the user to type in the name of an application, and the corresponding application will be launched. We could do this using a switch statement as in "C# Basics: Command Interpreter Using Methods". Or even better, we can use a Dictionary to store the relationship between application names and their path. First, add the following using at the top if it's not there already (e.g. if you're using SharpDevelop):

using System.Collections.Generic;

Next, our Dictionary, using the collection initialiser syntax as in "C# Basics: Morse Code Converter Using Dictionaries":

            Dictionary<string, string> programs = new Dictionary<string, string>()
            {
                { "notepad++", @"C:\tools\notepad++\notepad++.exe" },
                { "firefox", @"C:\tools\firefox\firefox.exe" }
            };

We can now accept user input and launch the appropriate program. Replace the two lines we wrote earlier (which include the call to Process.Start()) with this:

            Console.Write("Enter program to launch: ");
            string programName = Console.ReadLine();
            if (programs.ContainsKey(programName))
            {
                string path = programs[programName];
                Process.Start(path);
                Console.WriteLine("{0} launched from {1}", programName, path);
            }
            else
                Console.WriteLine("Unknown program");

The user gives us the name of the program he wants to launch. If that name exists in our dictionary, we get the corresponding path, and then launch it as we did before. If we try this now, it works pretty nicely:


Although this works pretty well, it isn't very flexible to have the program names hardcoded in your program code. Imagine you give this program to a friend. It wouldn't be very useful if he could only launch Firefox and Notepad++. What if he wanted to be able to launch SharpDevelop as well? And maybe in future he might want to add VLC as well. It obviously isn't convenient for you to have to change the code, recompile, and give him an updated program each time.

One option could be to store these program settings in a file and read it, but .NET provides us with a simpler option that exists specifically for this kind of scenario. .NET applications can optionally come with an application configuration file, which is usually called App.config. In fact, if, like me, you're using SharpDevelop 5 Beta 2, you should have one already (otherwise just add an Application Configuration File to your project):


When you build the application, App.config gets renamed to the name of the executable, plus a ".config", and is stored in the same folder:


In this App.config file, under the <configuration> node, we can add an <appSettings> node and store our settings. The settings have a key, which is a name that identifies them, and a value which is the value of the setting. Ours will be like this:

    <appSettings>
        <add key="notepad++" value="C:\tools\notepad++\notepad++.exe" />
        <add key="firefox" value="C:\tools\firefox\firefox.exe" />
    </appSettings>

With this done, we can now rewrite our program to use these settings. First, we need to add a reference to System.Configuration. To do this, right click on the name of the project in Solution Explorer, and select "Add Reference":


In the "Add Reference" window, locate "System.Configuration" and then click "OK".

Next, add the following using statement at the top:

using System.Configuration;

We can now use ConfigurationManager to obtain our app settings, like this:

        public static void Main(string[] args)
        {
            Console.Title = "Launcher";
           
            string firefoxPath = ConfigurationManager.AppSettings["firefox"];
            Console.WriteLine(firefoxPath);
           
            Console.ReadLine();
        }

...And here's what we see when we run this:


So now, all we need to do is let the user tell us which program he wants to launch, and find it in the AppSettings:

        public static void Main(string[] args)
        {
            Console.Title = "Launcher";
           
            Console.Write("Enter program to launch: ");
            string programName = Console.ReadLine();
           
            string path = ConfigurationManager.AppSettings[programName];
            if (path == null)
                Console.WriteLine("Unknown program.");
            else
            {
                Process.Start(path);
                Console.WriteLine("{0} launched from {1}", programName, path);
            }
           
            Console.ReadLine();
        }

The only thing worth noting here is that if the specified key does not exist in the AppSettings, retrieving that key via ConfigurationManager.AppSettings[] returns null, allowing us to take appropriate action in that case.

So now, when you give this program to a friend, he can just add the following line in the CsAppSettings.exe.config file that conveniently comes with the program:

         <add key="fiddler" value="C:\tools\fiddler2\Fiddler.exe" />

...and without further ado, he can now launch Fiddler as well:


Wonderful! :)

In this article, we learned how to start another program from our code, and we also learned how to work with application settings in an application configuration file.

Storing your application settings in an App.config file is convenient because they can be tweaked as needed, without having to recompile your program. These kinds of settings are best suited for settings that don't change frequently, so you just set them when you need them, and forget about them. In the next article, we'll learn about another kind of settings that are great for storing stuff like user preferences which can potentially change a lot.

Sunday, March 16, 2014

C: Rock, Scissors, Paper (using random numbers)

Hello everyone, and welcome back to the Ranch! :)

In my last C article, "C: Calculating the Average of Several Numbers", we learned how to work with numbers in C. This included using integer variables, input/output of integers, and arithmetic operations.

Today, we're going to take this further and learn how to generate random numbers in C. We'll use this to write a little Rock, Scissors, Paper game.

Pseudo-random numbers in C


So let's start off with a pretty empty program:

#include <stdio.h>

int main(int argc, char ** argv)
{
    return 0;
}

We can generate a random integer using the rand() function, which is defined in stdlib.h. This gives us a random number between 0 and a constant integer called RAND_MAX. We can output the value of RAND_MAX as we would any other integer, although its value is not guaranteed to be the same across different computers:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv)
{
    int a = rand();
    int b = rand();
    int c = rand();

    printf("RAND_MAX is: %d\n", RAND_MAX);
    printf("a is: %d\n", a);
    printf("b is: %d\n", b);
    printf("c is: %d\n", c);

    return 0;
}

Let us now run this program a few times and see what happens:


On my computer, RAND_MAX is defined as 2147483647, so each time I call rand(), it will give me a random number between 0 and 2147483647.

Another thing you'll see from the output is that each time I run the program, I get the same values for a, b and c. That isn't quite random, is it?

The reason why this is happening is that these random numbers aren't really random.  They are actually generated from a mathematical sequence, that takes a very, very long time to begin repeating itself, but which isn't truly random. These are called pseudo-random numbers. Imagine this sequence:

4, 29, 55, 12, 4, 7, 3, 97, 84, ...

This sequence seems pretty random; there isn't any pattern in it. So each time we get a random number with rand(), we'll get a different number: first 4, then 29, then 55, etc.

Our problem is that each time we run the program, we're starting from the beginning of the sequence, and this gives us the same values. So what we want to do is start from a different position each time.

We do this by seeding the pseudo-random number generator using the srand() function. Let's just add this line at the beginning of main():

    srand(100);

Let's run the program again:


You'll notice the numbers have changed, since we're using a different seed. However, each time we run the program, the same numbers are repeated. In fact we are still making the same mistake as before: we are using the same seed, and starting the pseudo-random number sequence from the same point each time.

In order to use a different seed each time we run the program, we can use the current time as the seed. We can use the time() function, defined in time.h, to give us the current time. So let's include that header file at the top...

#include <time.h>

...and replace our call to srand() with this:

srand(time(NULL));

When we run the program, things work as we expect, and we get different pseudorandom numbers each time we run:


Scaling random numbers


Great. Now, the numbers we are generating are a little bit big. For example, for Rock, Scissors, Paper, we don't need a number between 0 and 2147483647; all we need is a number between 1 and 3 (both inclusive), to represent either rock, scissors, or paper. We can limit the range of a pseudorandom number by dividing it by the maximum we want, and extracting the remainder. This is done using the modulus (%) operator, which gives us the remainder of a division:

    int a = rand() % 10;
    int b = rand() % 10;
    int c = rand() % 10;

Let's say rand() gives us 55. If we divide 55 by 10, then the remainder can be at most 9. So what we're doing above is limiting each random number to the range 0 to 9 (both inclusive). We'll need to add 1 to the number by which we're dividing, in order to make it inclusive (i.e. between 0 and 10 in this case).

What if we need a minimum value that is not zero? In short, we declare a general-purpose function that returns random integers between two integers (both inclusive) like this:

// returns a random number between min and max, both inclusive)
int randomInt(int min, int max)
{
    return min + (rand() % (max - min + 1));
}

We can then use this function from within our main() like this, to give us random numbers between 1 and 10:

    int a = randomInt(1, 10);
    int b = randomInt(1, 10);
    int c = randomInt(1, 10);

And voilà:


Rock, Scissors, Paper in C


OK, so now that we know how to generate pseudorandom numbers, we can write out game of Rock, Scissors, Paper. In this game, two people independently choose one of rock, scissors or paper, and state their choice at the same time. The outcome is then as follows:

  • Rock beats scissors (breaks it).
  • Scissors beats paper (cuts it).
  • Paper beats rock (wraps it).

To start off, let's throw away all our code in main(), but keep our randomInt() function:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// returns a random number between min and max, both inclusive)
int randomInt(int min, int max)
{
    return min + (rand() % (max - min + 1));
}

int main(int argc, char ** argv)
{
    // code goes here

    return 0;
}

First, we add code to accept user input:

    int input = -1;

    while (input != 0)
    {
        printf("Choose...\n");
        printf("   1 for rock\n");
        printf("   2 for scissors\n");
        printf("   3 for paper\n");
        printf("or 0 to exit\n");

        scanf("%d", &input);
    }

The user will choose a number between 1 and 3 to represent rock, scissors, or paper respectively. A while loop repeats the game until the user enters 0 to exit the game. We have already used for loops in C: Calculating the Average of Several Numbers, but a while loop will simply keep executing the code within curly brackets as long as the condition within round brackets is true, in this case as long as input is not zero:


Once the human player has chosen, the computer player makes his choice at random:

       int computerChoice = randomInt(1, 3);

We can then display the computer's choice:

       switch(computerChoice)
       {
           case 1: printf("Computer chooses rock\n"); break;
           case 2: printf("Computer chooses scissors\n"); break;
           case 3: printf("Computer chooses paper\n"); break;
       }

A switch statement allows us to specify separate code to be executed depending on the value of a variable. In this case, if computerChoice is 1, we write that the computer has chosen rock, and similarly for the other choices. Note that each case in a switch statement should always end in a break statement; otherwise unexpected things may happen. :)

Finally, we can add the game logic to check who won:

       if (input == computerChoice)
       {
           printf("Game ends in a draw.\n");
       }
       else if (input == 1 && computerChoice == 2)
       {
          printf("Rock beats scissors! You win!\n");
       }
       else if (input == 2 && computerChoice == 3)
       {
          printf("Scissors beats paper! You win!\n");
       }
       else if (input == 3 && computerChoice == 1)
       {
          printf("Paper beats rock! You win!\n");
       }
       else if (computerChoice == 1 && input == 2)
       {
          printf("Rock beats scissors! Computer wins!\n");
       }
       else if (computerChoice == 2 && input == 3)
       {
          printf("Scissors beats paper! Computer wins!\n");
       }
       else if (computerChoice == 3 && input == 1)
       {
          printf("Paper beats rock! Computer wins!\n");
       }

Using a cascade of if statements, we compare the user input with the computer's random choice and see who won. The == operator allows us to compare two integers and determine whether they are equal. The && operator, on the other hand, is a boolean AND operator. If both conditions around the && operator are true, then the printf() statement within the curly brackets of that if statement is executed.

We can now actually play our game:


Summary


Great! :) We have a fully working Rock, Scissors, Paper game here. And in creating it, we learned about pseudo-random numbers, while loops, if statements, switch statements, and also a few operators including == (is equal to), != (is not equal to) and && (boolean AND). Below is the full code.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// returns a random number between min and max, both inclusive)
int randomInt(int min, int max)
{
    return min + (rand() % (max - min + 1));
}

int main(int argc, char ** argv)
{
    int input = -1;

    while (input != 0)
    {
        printf("Choose...\n");
        printf("   1 for rock\n");
        printf("   2 for scissors\n");
        printf("   3 for paper\n");
        printf("or 0 to exit\n");

        scanf("%d", &input);

       int computerChoice = randomInt(1, 3);

       switch(computerChoice)
       {
           case 1: printf("Computer chooses rock\n"); break;
           case 2: printf("Computer chooses scissors\n"); break;
           case 3: printf("Computer chooses paper\n"); break;
       }

       if (input == computerChoice)
       {
           printf("Game ends in a draw.\n");
       }
       else if (input == 1 && computerChoice == 2)
       {
          printf("Rock beats scissors! You win!\n");
       }
       else if (input == 2 && computerChoice == 3)
       {
          printf("Scissors beats paper! You win!\n");
       }
       else if (input == 3 && computerChoice == 1)
       {
          printf("Paper beats rock! You win!\n");
       }
       else if (computerChoice == 1 && input == 2)
       {
          printf("Rock beats scissors! Computer wins!\n");
       }
       else if (computerChoice == 2 && input == 3)
       {
          printf("Scissors beats paper! Computer wins!\n");
       }
       else if (computerChoice == 3 && input == 1)
       {
          printf("Paper beats rock! Computer wins!\n");
       }
    }

    return 0;
}

Friday, March 14, 2014

C#: Authenticating with Active Directory

Hi! :)

If you work in a corporate environment, chances are that your Windows machine is connected to a domain based on Active Directory. In today's article, we're going to write a very simple program that allows us to verify a user's credentials for the domain using Active Directory.

In order to try this out, you're going to need an Active Directory domain. In my case, I installed Windows Server 2008 R2 and followed these instructions to set up a domain, which I called "ranch.local". You may also be able to connect to your domain at work to save yourself the trouble of setting this up.

Let us now create a new Console Application using either SharpDevelop or Visual Studio. After adding a reference to System.DirectoryServices.AccountManagement, add the following statement near the top of your Program.cs file:

using System.DirectoryServices.AccountManagement;

Next, remove any code in Main() and add a simple prompt for the username and password to authenticate against Active Directory:

            // prompt for username

            Console.Write("Username: ");
            string username = Console.ReadLine();

            // prompt for password

            Console.Write("Password: ");
            string password = Console.ReadLine();

For the authentication part, we can use a simple method described here. After obtaining a reference to the domain using the PrincipalContext class (specifying the domain as a parameter), we simply use the ValidateCredentials() method to perform the authentication. This gives us a boolean value indicating whether the authentication was successful or not.

            // authenticate

            using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "RANCH"))
            {
                bool authenticated = pc.ValidateCredentials(username, password);

                if (authenticated)
                    Console.WriteLine("Authenticated");
                else
                    Console.WriteLine("Get lost.");
            }

At this point, we need only add a simple statement to wait for user input before letting the application terminate:

            Console.ReadLine();

Now, we can build our application and test it on the server (or on any machine that is part of the domain). First, let's try a valid login:


Very good! And now, a user that doesn't even exist:


Excellent! As you can see, it only takes a couple of lines of code to perform authentication against Active Directory. I hope you found this useful. Follow the Ranch to read more articles like this! :)