Decision Making in C#

Decision Making

The Crash Course

  • if statements work just like they do in C++ and Java:
if (condition) 
{ 
    statement; 
    statement; 
    statement; 
}
else if(another condition)
{
    statement;
    statement;
}
else
{
    statement;
    statement;
}
  • Likewise, the ==, !=, <, >, <=, >= operators also work like in many other languages, checking if two things are equal, not equal, less than, greater than, less than or equal to, and greater than or equal to.
  • The ! operator negates boolean types.
  • The && (and operator) and || (or operator) allow you to compare multiple things at one time, and work identical to the way they work in C++ and Java.
  • if statements can be nested.

Introduction

Any program that does any real work will have to make decisions. These decisions are based on meeting certain conditions—or rather, running code only some of the time when a particular condition or state is met. The central piece of decision-making is a special C# statement called an if statement. We'll start by looking at the if statement, along with a few related statements, then we'll look at a variety of ways to compare two values. We'll then look at a few other special operators called logical operators (not nearly as scary as it sounds, I promise!) that help us make more sophisticated conditions.

The if statement

Imagine, if you will, a scenario where a teacher is assigning grades and wants to know, based on a student's test score, what grade they should get. (In the real world, this is pretty easy to do, but give me a break, I need an example that requires decision-making without being too complicated!)

The basic process is for the teacher to take a look at the student's score, and if it is 90 or higher, the student gets an 'A'. But if they're lower than that, but still at 80 or higher, then they get a 'B', and so on, down to a failing grade. Basically, in order to do this, you need to make decisions based on certain things. We do things conditionally—meaning it only happens some of the time.

We only give some students A's, while others get B's, and others fail.

In this tutorial, we're going to go through the process of making a program that will determine a student's grade based on their score.

So let's start at the beginning. In C#, you can check to see if two things are equal by using an if statement. An if statement will look something like the following:

if(score == 100)
{
    // Any code between the curly braces gets executed by the program only when 
    // the condition in the parentheses is true.
    Console.WriteLine("Perfect score!  You win!");
}

That should be fairly straightforward. There are a few parts to a basic if statement. We start off by using the if keyword. Then, in parentheses, we put the condition we're looking for. In a minute, we'll discuss some more cool and useful ways to make all sorts of conditions. We then use the curly braces ({ and }) to show a code block that should only be run when the condition is true.

So to put this in the context of a "complete" program, here's what this might look like in your code:

// Everything up here before the if statement will always be executed.
int score;
 
Console.Write("Enter your score: ");        // Writes the text out without going to the next line.
string scoreAsText = Console.ReadLine();
score = Convert.ToInt32(scoreAsText);
 
if (score == 100)
{
    // The stuff here inside of the if statement's code block only gets executed when the condition is met--
    // in this case, if the score is 100.
 
    Console.WriteLine("Perfect score! You win!");
}
 
// Everything down here after the if statement will also always be executed.
Console.ReadKey();

The else statement

So what if you want to do something in one case and something else if that's not the case? For instance, what if you want to print out "You win!" if the student got 100, but "You lose!" if they didn't? That's easy to do, using the else keyword:

if(score == 100)
{
    // This code gets executed when the condition is met.
    Console.WriteLine("Perfect score! You win!");
}
else
{
    // This code gets executed when it is not.
    Console.WriteLine("Not a perfect score.  You lose.");
}

The important thing to remember here (and use it to your advantage) is that one or the other blocks of code is going to get executed. If it does one, it won't do the other, but it will for sure do one of them.

else/if statements

You can get more creative with if and else though, too, stringing together many of them:

if(score == 100)
{
    Console.WriteLine("Perfect score!  You win!");
}
else if(score == 99)
{
    Console.WriteLine("Missed it by THAT much."); // Get Smart reference, anyone?
}
else if(score == 0)
{
    Console.WriteLine("Seriously, dude, you had to have been TRYING to get that bad of a score.");
}
else
{
    Console.WriteLine("Ah, come on!  That's just boring.");
    Console.WriteLine("Seriously.  Next time, pick a more interesting number.");
    Console.WriteLine("OK, basically, I'm only doing this to make sure you ");
    Console.WriteLine("know that as many lines of code as you want can go in here.");
}

So here, one (and only one) of the blocks will get executed, but depending on the score, it will be different.

Relational Operators

So that's the basics of decision-making. Let's take a look now at some better and more powerful ways you can specify conditions (you know, the part that says score == 100).

The == operator that we've just been introduced to is called a relational operator, which is a fancy way of saying "an operator that compares two things." There are lots of other ones.

For instance, the != operator checks to see if two things are not equal to each other. This works just like the == operator:

if(score != 100)
{
    // Anything in here will be executed as long as the score is //not// 100.
}

Then there are the > and < operators, which determine if something is greater than or less than something else. These work just like they do in math:

if(score > 90)
{
    // This will only be executed if the score is more than 90.
    Console.WriteLine("You got an 'A'!");
}
 
if(score < 60)
{
    // This will only be executed if the score is less than 60.
    Console.WriteLine("You got an 'F'.  Sorry.");
}

Of course, you may have noticed that this isn't exactly what we set out to do originally. We wanted to give an A if they scored at least 90. In this case, 90 doesn't result in an A because 90 is not greater than 90.

This brings us to the last two relational operators >= and <=. These two mean "greater than or equal to" and "less than or equal to" respectively.

if(score >= 90)
{
    // This will only be executed if the score is 90 or higher...
    // Subtly different from the above example because it
    // also picks up 90.
    Console.WriteLine("You got an 'A'!");
}

This, by the way, is basically enough to write the full program we set out to do:

int score;
 
Console.Write("Enter your score: ");        // Writes the text out without going to the next line.
string scoreAsText = Console.ReadLine();
score = Convert.ToInt32(scoreAsText);
 
// This if-statement is separate from the rest of them. By the way, that has nothing to do with the blank line
// between this statement and the 'if(score >= 90)' line, but rather, because that starts all over with a brand
// new if statement.
if (score == 100)
{
    Console.WriteLine("Perfect score!  You win!");
}
 
// This drops down and checks each condition in turn, until it finds the first one that is true, at which
// point, it executes the chosen code block, then jumps down to after the end of the whole if/else code.
if (score >= 90)
{
    Console.WriteLine("You got an A.");
}
else if (score >= 80)
{
     Console.WriteLine("You got a B.");
}
else if (score >= 70)
{
    Console.WriteLine("You got a C.");
}
else if (score >= 60)
{
    Console.WriteLine("You got a D.");
}
else
{
    Console.WriteLine("You got an F.");
}

Using bool in Decision Making

Remember when we first discussed data types, and how I told you about the bool type and that it would turn out to be useful? Well, here it is. You can use variables with the bool type in making decisions; in fact, it is very common to do so. For instance, check out this block of code that determines if a player has enough points to pass the level:

int score = 45; // Eventually, we'll get to a point where this can change as a player plays the game.
int pointsNeededToPass = 100;
 
bool levelComplete;
 
if(score >= pointsNeededToPass)
{
    levelComplete = true;
}
else
{
    levelComplete = false;
}
 
if(levelComplete)
{
    // We'll be able to do more here later as we learn more about C#.
    Console.WriteLine("You've beaten the level!");
}

Note, also, that relational operators return a bool value—meaning you can use a relational operator like == or > to directly assign a value to a bool:

int score = 45; // Eventually, we'll get to a point where this can change as a player plays the game.
int pointsNeededToPass = 100;
 
// You don't actually need the parentheses here, but it makes it more readable to me.
bool levelComplete = (score >= pointsNeededToPass);
 
if(levelComplete)
{
     // We'll be able to do more here later, as we learn more C#
    Console.WriteLine("You've beaten the level!");
}

The ! Operator

A second ago, we looked at the != operator, which sees if two things are not equal. There's another way that we'll see the ! sign, and that is to negate conditions. This is going to be more powerful in a second when we discuss conditional operators, but let's take a quick look.

The ! operator just takes the opposite value of whatever it is used on. So, for instance:

bool levelComplete = (score >= pointsNeededToPass);
 
if(!levelComplete)
{
    Console.WriteLine("You haven't won yet.  Better keep trying...");
}

You can also combine this with all of the conditional operators we've talked about, though the ! operator has "higher precedence" than the relational operators, meaning it happens first, before the comparison. If you want to do the comparison first, then negate it, you have to use parentheses. To illustrate:

if(!(score > oldHighScore))
{
}
 
// that's effectively the same as:
if(score <= oldHighScore)
{
}

You'll discover that there are always lots of ways to accomplish the same thing. (For the record, you should always choose the one that is the easiest to understand when you come back to read it later. You'll be glad you did.)

Conditional Operators: && and || (And and Or)

There are a lot of ways your conditions could be a lot more complicated. For instance, imagine you have a game where the player controls a spaceship that has both shields and armor, and the player only dies when both shields and armor are gone. You will need to check against both things, rather than just one.

Here's where conditional operators come into play. C# has an and operator, which looks like this: &&, and an or operator that looks like this: ||. You can use these to check multiple things at once:

int shields = 50;
int armor = 20;
 
if(shields <= 0 && armor <= 0)
{
    Console.WriteLine("You're dead.");
}

This means, "if shields are less than or equal to zero, and armor is less than or equal to zero". Both parts of the condition have to be true.

The || operator works in a similar way, except that only one of the two sides needs to be true:

int shields = 50;
int armor = 20;
 
if(shields > 0 || armor > 0)
{
    Console.WriteLine("You're still alive!  Keep going!");
}

One thing worth mentioning is that with either of these, the computer will do "lazy evaluation." Meaning that it won't check the second part unless it knows it needs to. So, for instance, in the example above, the computer will always check to see if shields is greater than 0, but it only bothers checking if armor is greater than 0 if shields is 0.

Also, you can combine lots of these together and, along with parentheses, make some pretty crazy conditions. Anything you want is possible, though readability may quickly become an issue. This leads us to the next section, which might provide an alternative approach that may be more readable.

Nesting if Statements

One other thing that needs to be mentioned is that you can put if statements (and if/else statements) inside of other if statements. This is called nesting them.

For example:

if(shields <= 0)
{
    if(armor <= 0)
    {
        Console.WriteLine("Your shields and armor are both zero!  You're dead!");
    }
    else
    {
        Console.WriteLine("Your shields are gone, but you still have armor left.  You're lucky to be alive!");
    }
}
else
{
    Console.WriteLine("You still have shields left.  The world is safe.");
}

It doesn't have to end there, either. You could nest if statements inside of if statements inside of if statements inside of…. (Wait, wasn't that the premise behind Inception? The fact that it is doable doesn't necessarily make it a good idea. Lots of nesting means the code is less readable. Use it when there's a need for it (and there will be), but you don't need to overdo it.

What's Next?

if statements are a key part of programming. They let you make decisions about how things are going to work. No programming language is complete without some form of if statement. (This, by the way, is why HTML is not a "real" programming language.)

The next thing we'll take a look at is a construct called a switch statement that accomplishes a lot of the same things as an if statement, but in a slightly different way.