Programming Concepts


For the rest of this chapter, we are going to explore basic programming techniques. We will be using Torque Script for all of our code examples and running our little programs in the Torque Engine to see what they do.

Now, we just covered the simple math problem in the previous section. I showed you what the program looked liked in binary machine language, hex machine language, assembly language, and finally C/C++. Well, here is one more version—Torque Script:

 %a=4;     // (1) %b=6;     // (2) %c=%a+%b; // (3) 

Notice the similarity to C/C++? Even the comments are done the same way!

As demonstrated, Torque Script is much like C/C++. There are a few exceptions, the most notable being that Torque Script is typeless and does not require forward declarations of variables. Also, as you can see for yourself in the preceding code, Torque Script requires scope prefixes (the percent signs) on its variable names.

start sidebar
Typeless? Forward Declarations? Huh?

In many languages, variables have a characteristic called type. In its simplest form, a type merely specifies how much memory is used to store the variable.Torque Script doesn't require you to specify what type your variable has. In fact, there is no way to do it!

Forward declarations are a construct whereby the programmer must first indicate, usually at the beginning of a file or a subroutine block, what variables will be used and what their types are.Torque Script also doesn't require this and again provides no mechanism for using forward declarations.

So now that you know what types and forward declarations are, you can forget about them!

end sidebar

The goal for you to achieve by the end of this chapter is the ability to put together simple programs to solve problems and have enough understanding of program techniques to make sensible decisions about the approaches to take.

How to Create and Run the Example Programs

There is an ancient and well-understood programming cycle called the Edit-Compile-Link-Run cycle. The same cycle applies with Torque, with the exception being that there is no link step. So for us, it can be thought of as the Edit-Compile-Run cycle. A further wrinkle to toss in is the fact that Torque will automatically compile a source file (that is, a program file that ends with .cs) into the binary byte code file (ends with .cs.dso), if there is no binary version of the file, or if the source file has changed since the last binary was created.

So I guess my point is, for us the cycle can now be regarded as the Edit-Run cycle.

  • Put all user programs in the folder C:\3DGPAi1\CH2 as filename.cs where "filename" is a name you've either made up yourself or one that I've suggested here in the book.

  • Run from command shell tge -CH2 filename.cs.

Hello World

Our first program is somewhat of a tradition. Called the Hello World program, it is used as an early confidence builder and test program to make sure that the Gentle Reader (that would be you, if you are reading this book!) has everything in place on his computer to successfully edit, compile, and run a program.

So, assuming that you've installed both UltraEdit and the Torque Game Engine, use your newly learned UltraEdit skills to create a new file with the name HelloWorld.cs and save it in the folder C:\3DGPAi1\CH2. Type into the file these lines of code:

 // ======================================================================== //  HelloWorld.cs // //  This module is a program that prints a simple greeting on the screen. // // ======================================================================== function main() // -------------------------------------- //     Entry point for the program. // -------------------------------------- {    print("Hello World"); } 

Save your work. Now, use the following procedure to run your program:

  1. From your Windows Start menu select the Start, Run.

  2. Type command in the edit box offered. This will open a Command window or MS-DOS Prompt window.

  3. In the new window at the command prompt (the blinking cursor), type cd C:\3DGPAi1 and then press Enter.

  4. Next, type tge -ch2 HelloWorld.cs. A Torque window will open up, and you should see something like Figure 2.10, with "Hello World" in yellow at the upper left of the screen. Cool, huh?

click to expand
Figure 2.10: Output of the Hello World program.

Tip

If you don't get the expected result on your screen, then look in the log file, named console.log, located in the C:\3DGPAi1 folder. If there were any errors in your program, diagnostic information will be deposited there. It might be something as simple as a typo in the file name.

Let's have a closer look at the code. The first thing you will notice is this stuff:

 // ======================================================================== //  HelloWorld.cs // //  This module is a program that prints a simple greeting on the screen. // // =============================================================== 

This is the module header block. It is not executable code—it's what we call a comment. The double-slash operator ("//") tells the Torque Engine to ignore everything from the slashes to the end of the line.

So if the engine ignores it, why do we use it? Well, it's included in order to document what the module does so that later when we've completely forgotten the details, we can easily refresh our memory. It also is included to help other programmers who may come along and need to understand the module so they can add new features or fix bugs.

There are no real rules regarding the format of these headers, but most programmers or development shops have some sort of template that they want followed. At a minimum, the header should include the module file name, copyright notices, and a general description of what the code in the module is for. Sometimes we might include other details that are necessary for a person to understand how the module is used.

Then there is this part:

 function main() 

That is executable code. It is the declaration of the function block called main(). Following that, there is this:

 // -------------------------------------------- //    Entry point for the program. // -------------------------------------------- 

This is the function header. The function header is included in order to describe the specifics of a function—what it does, how it does it, and so on. In this case it is fairly simple, but function headers can get to be quite descriptive, as you'll see later. Again, this is not executable code (note the double slash) and is not required to make your program work.The dashes could just as well be stars, equals signs, or nothing at all. It is good practice to always use function headers to describe your functions.

Finally comes this:

 {    print("Hello World"); } 

That would be the function body—the guts of the function where the work is done. The function body is also sometimes called a function block, and more generically (when used in other contexts that you'll see later) called a code block.

All sample programs in this chapter must have something called function main(). Don't worry about why that is for the moment—we'll get into that later. Just take it as a given that it is necessary for your programs to work properly.

It is important to note the way a function block is made. It always begins with the keyword function followed by one or more spaces and whatever name you want it to have. After the name comes the argument list (or parameter list). In this case there are no parameters. Then comes the opening, or left, brace (or curly bracket). After the opening brace comes the body of the function, followed by the closing, or right, brace.

All functions have this same structure. Some functions can be several pages long, so the structure may not be immediately obvious, but it's there.

The actual code that does anything interesting is a single line. As you know by now, the line simply prints the text "Hello World" in the Torque window.

Note

Experienced C programmers will recognize the main function as the required initial entry point for a C program, although the syntax is slightly different. Torque doesn't require this organization for its scripts—it is purely for learning purposes.

Expressions

When we write program code, most of the lines, or statements, that we create can be evaluated. A statement can be a single Torque Script line of any kind terminated by a semicolon, or it can be a compound statement, which is a sequence of statements enclosed in left and right braces that acts as a single statement. A semicolon does not follow the closing right brace. Here is an example of a statement:

 print("Hi there!"); 

Here is another example:

 if (%tooBig == true) print("It's TOO BIG!"); 

And here is one final example of a valid statement:

     {         print("Nah! It's only a little motorcycle.");     } 

Statements that can be evaluated are called expressions. An expression can be a complete line of code or a fragment of a line, but the important fact is that it has a value. In Torque the value may be either a number or text (a string)—the difference is in how the value is used. Variables are explained in the next section, but I'll sneak a few in here without detailed coverage in order to illustrate expressions.

Here is an expression:

     5 + 1 

This expression evaluates to 6, the value you get when 5 and 1 are added.

Here is another expression:

    %a = 67; 

This is an assignment statement, but more importantly right now, it is an expression that evaluates to 67.

Another:

    %isOpen = true; 

This expression evaluates to 1. Why? Because true evaluates to the value 1 in Torque. Okay, so I hadn't told you that yet—sorry about that. Also, false evaluates to 0. We can say the statements evaluate to true or false, instead of 1 and 0. It really depends on whatever makes sense in the usage context. You'll notice that the evaluation of the statement is determined by whatever expression is to the right of the equal sign. This is a pretty hard-and-fast rule.

Consider this code fragment:

    %a = 5;    if (%a > 1 ) 

What do you figure that the (%a > 1 ) evaluates to, if %a has been set to 5? That's right— it evaluates to true. We would read the line as "if %a is greater than 1." If it was written as (%a > 10 ), it would have been false, because 5 is not greater than 10.

Another way we could write the second line is like this:

    if ( (%a > 1 ) == true ) 

It would be read as "if the statement that %a is greater than 1 is true." However, the Department of Redundancy Department could have written that example. The first way I showed you is more appropriate.

Just for your information, in the preceding examples, %a and %isOpen are variables, and that's what is coming up next.

Variables

Variables are chunks of memory where values are stored. A program that reads a series of numbers and totals them up will use a variable to represent each number when it's entered and another variable to represent the total. We assign names to these chunks of memory so that we can save and retrieve the data stored there. This is just like high school algebra, where we were taught to write something like "Let v stand for the velocity of the marble" and so on. In that case v is the identifier (or name) of the variable. Torque Script identifier rules state that an identifier must do the following:

  • It must not be a Torque Script keyword.

  • It must start with an alphabetical character.

  • It must consist only of alphanumeric characters or an underscore symbol ( _ ).

A keyword is an otherwise valid identifier that has special significance to Torque. Table 2.3 gives a keyword list. For the purposes of Torque identifiers, the underscore symbol ( _ ) is considered to be an alphanumeric character. The following are valid variable identifiers:

Table 2.3: Torque Script Keywords

Keyword

Description

break

Breaks execution out of a loop.

case

Indicates a choice in a switch block.

continue

Causes execution to continue at top of loop.

default

Indicates the choice to make in a switch block when no cases match.

do

Indicates start of a do-while type loop block.

else

Indicates alternative execution path in an if statement.

false

Evaluates to 0, the opposite of true.

for

Indicates start of a for loop.

function

Indicates that the following code block is a callable function.

if

Indicates start of a conditional (comparison) statement.

new

Creates a new object data block.

return

Indicates return from a function.

switch

Indicates start of a switch selection block.

true

Evaluates to 1, the opposite of false.

while

Indicates start of a while loop.

isOpen Today

X

the_result

item_234

NOW

These are not legal identifiers:

5input

miles-per-hour function

true

+level

It's up to you as the programmer to choose the identifiers you want to use. You should choose them to be significant to your program and what it is doing. You should always try to use meaningful identifiers.You should note that Torque is not case-sensitive. Lowercase letters are not treated as distinct from uppercase letters.

You assign values to variables with an assignment statement:

 $bananaCost = 1.15; $appleCost = 0.55; $numApples = 3; $numBananas = 1; 

Notice that each variable has a dollar sign ("$") preceding it. This is the scope prefix. This means that the variable has global scope—it can be accessed from anywhere in your program, inside any function, or even outside functions and in different program files.

There is another scope prefix—the percent sign ("%"). The scope of variables with this prefix is local. This means that the values represented by these variables are valid only within a function, and only within the specific functions where they are used. We will delve into scoping in more detail later.

Using our fruit example, we can calculate the number of fruit as follows:

 [$numFruit = $numBananas + $numApples; 

And we can calculate the total cost of all the fruit like this:

 $numPrice = ($numBananas * $bananaCost) + ($numApples * $appleCost); 

Here is a complete small program you can use to try it out yourself.

 // ======================================================================== //  Fruit.cs // //  This module is a program that prints a simple greeting on the screen. //  This program adds up the costs and quantities of selected fruit types //  and outputs the results to the display // ======================================================================== function main() // ------------------------------------ //      Entry point for the program. // ------------------------------------ {  $bananaCost=1.15;// initialize the value of our variables  $appleCost=0.55; //   (we don't need to repeat the above  $numApples=3;    //   comment for each initialization, just  $numBananas=1;   //   group the init statements together.)  $numFruit=0;     // always a good idea to initialize *all* variables!  $total=0;        // (even if we know we are going to change them later)  print("Cost of Bananas(ea.):$"@$bananaCost);                   // the value of $bananaCost gets concatenated to the end                   // of the "Cost of Bananas:" string. Then the                   // full string gets printed. same goes for the next 3 lines  print("Cost of Apples(ea.):$"@$appleCost);  print("Number of Bananas:"@$numBananas);  print("Number of Apples:"@$numApples);  $numFruit=$numBananas+$numApples; // add up the total number of fruits  $total = ($numBananas * $bananaCost) +                ($numApples * $appleCost); // calculate the total cost                //(notice that statements can extend beyond a single line)  print("Total amount of Fruit:"@$numFruit); // output the results  print("Total Price of Fruit:$"@$total@"0");// add a zero to the end                                  // to make it look better on the screen } 

Save the program in the same way you did the Hello World program. Use a name like fruit.cs and run it to see the results. Note that the asterisk ("*") is used as the multiplication symbol and the plus sign ("+") is used for addition. These operators—as well as the parentheses used for evaluation precedence—are discussed later in this chapter.

Arrays

When your Fruit program runs, a variable is accessed in expressions using the identifier associated with that variable. At times you will need to use long lists of values; there is a special kind of variable called an array that you can use for lists of related values. The idea is to just use a single identifier for the whole list, with a special mechanism to identify which specific value—or element—of the list you want to access. Each value has numerical position within the array, and we call the number used to specify the position the index of the array element in question.

Let us say you have a list of values and you want to get a total, like in the previous example. If you are only using a few values (no more than two or three), then a different identifier could be used for each variable, as we did in the Fruit program.

However, if you have a large list—more than two or three values—your code will start to get awkwardly large and hard to maintain. What we can do is use a loop, and iterate through the list of values, using the indices. We'll get into loops in detail later in this chapter. Here is a new version of the Fruit program that deals with more types of fruit. There are some significant changes in how we perform what is essentially the same operation. At first glance, it may seem to be more unwieldy than the Fruit program, but look again, especially in the computation section.

 // ======================================================================== //  FruitLoopy.cs // //  This module is a program that prints a simple greeting on the screen. //  This program adds up the costs and quantities of selected fruit types //  and outputs the results to the display. This module is a variation //  of the Fruit.cs module // ======================================================================== function main() // --------------------------------------------- //      Entry point for the program. // --------------------------------------------- {    //    // ----------------- Initialization -----------------    //    %numFruitTypes = 5; // so we know how many types are in our arrays    %bananaIdx=0;    // initialize the values of our index variables    %appleIdx=1;    %orangeIdx=2;    %mangoIdx=3;    %pearIdx=4;    %names[%bananaIdx] = "bananas"; // initialize the fruit name values    %names[%appleIdx] = "apples";    %names[%orangeIdx] = "oranges";    %names[%mangoIdx] = "mangos";    %names[%pearIdx] = "pears";    %cost[%bananaIdx] = 1.15; // initialize the price values    %cost[%appleIdx] = 0.55;    %cost[%orangeIdx] = 0.55;    %cost[%mangoIdx] = 1.90;    %cost[%pearIdx] = 0.68;    %quantity[%bananaIdx] = 1; // initialize the quantity values    %quantity[%appleIdx] = 3;    %quantity[%orangeIdx] = 4;    %quantity[%mangoIdx] = 1;    %quantity[%pearIdx] = 2;    %numFruit=0;    // always a good idea to initialize *all* variables!    %totalCost=0;   // (even if we know we are going to change them later)    //    // ----------------- Computation -----------------    //    // Display the known statistics of the fruit collection    for (%index = 0; %index < %numFruitTypes; %index++)    {       print("Cost of " @ %names[%index] @ ":$" @ %cost[%index]);       print("Number of " @ %names[%index] @ ":" @ %quantity[%index]);    }    // count up all the pieces of fruit, and display that result    for (%index = 0; %index <= %numFruitTypes; %index++)    {       %numFruit = %numFruit + %quantity[%index];    }    print("Total pieces of Fruit:" @ %numFruit);    // now calculate the total cost    for (%index = 0; %index <= %numFruitTypes; %index++)    {       %totalCost = %totalCost + (%quantity[%index]*%cost[%index]);    }    print("Total Price of Fruit:$" @ %totalCost); } 

Type this program in, save it as C:\3DGPAi1\book\FruitLoopy.cs, and then run it.

Of course, you will notice right away that I've used comments to organize the code into two sections, initialization and computation. This was purely arbitrary—but it is a good idea to label sections of code in this manner, to provide signposts, as it were. You should also notice that all the variables in the program are local, rather than global, in scope. This is more reasonable for a program of this nature, where having everything contained in one function puts all variables in the same scope.

Next you will see that I've actually created three arrays: name, cost, and quantity. Each array has the same number of elements, by design. Also, I have assigned appropriately named variables to carry the index values of each of the fruit types. This way I don't need to remember which fruit has which index when it comes time to initialize them with their names, prices, and counts.

Then it is just a simple matter of looping through the list to perform the operation I want.

Elegant, huh? But it could be better. See if you can find a way to reduce the number of lines of code in the computation section even more, and write your own version and try it out for yourself. I've written my own smaller version; you can find it in the C:\3DGPAi1\Book\Exercises folder, named ParedFruit.cs.

For a further illuminating exercise, try this: Rewrite FruitLoopy.cs to perform exactly the same operations, but without using arrays at all. Go ahead—take some time and give it a try. You can compare it with my version in the C:\3DGPAi1\Book\Exercises folder, named FermentedFruit.cs.

Now, the final exercise is purely up to you and your mind's eye: Imagine that you have 33 types of fruit, instead of five. Which program would you rather modify—ParedFruit.cs or FermentedFruit.cs? Can you see the advantage of arrays now?

Another thing to point out is that the initialization section of the code would probably read in the values from a database or an external file with value tables in it. It would use a loop to store all the initial values—the names, costs, and quantities. Then the code would really be a lot smaller!

To review, an array is a data structure that allows a collective name to be given to a group of elements of the same type. An individual element of an array is identified by its own unique index (or subscript).

An array can be thought of as a collection of numbered boxes, each containing one data item. The number associated with the box is the index of the item. To access a particular item, the index of the box associated with the item is used to access the appropriate box. The index must be an integer and indicates the position of the element in the array.

Strings

We've already encountered strings in our earlier example programs. In some languages strings are a special type of array, like an array of single characters, and can be treated as such. In Torque, strings are in essence the only form of variable. Numbers and text are stored as strings. They are handled as either text or numbers depending on which operators are being used on the variables.

As we've seen, two basic string operations are assignment and concatenation, as illustrated here:

 %myFirstName = "Ken"; %myFullName = %myFirstName @ " Finney"; 

In the first line, the string "Ken" is assigned to %myFirstName, then the string "Finney" is concatenated (or appended) to %myFirstName, and the result is assigned to %myFullName. Familiar stuff by now, right? Well, try this one on for size:

 %myAge = 30;              // (actually it isn't you know !) %myAge = %myAge + 12;    // getting warmer ! 

At this point, the value in %myAge is 42, the sum of 30 and 12. Now watch this trick:

 %aboutMe = "My name is " @ %myFullName @ " and I am " @ %myAge @ " years old."; 

I'm sure you can figure out what the value of the variable %aboutMe is. That's right, it's one long string—"My name is Ken Finney and I am 42 years old."—with the number values embedded as text, not numbers. Of course, that isn't my age, but who's counting?

What happened is that the Torque Engine figured out by the context what operation you wanted to perform, and it converted the number to a string value before it added it to the larger string.

There is another form of string variable called the tagged string. This is a special string format used by Torque to reduce bandwidth utilization between the client and the server. We'll cover tagged strings in more detail in a later chapter.

Operators

Table 2.4 is a list of operators. You will find it handy to refer back to this table from time to time.

Table 2.4: Torque Script Operators

Symbol

Meaning

+

Add

Subtract

*

Multiply

/

Divide

%

Modulus

++

Increment by 1

Decrement by 1

+=

Addition totalizer

-=

Subtraction totalizer

*=

Multiplication totalizer

/=

Division totalizer

%=

Modulus totalizer

@

String append

( )

Parentheses—operator precedence promotion

[ ]

Brackets—array index delimiters

{ }

Braces—indicate start and end of code blocks

SPC

Space append macro (same as @ " " @)

TAB

Tab append macro (same as @ "\t" @)

NL

New line append (same as @ "\n" @)

~

(Bitwise NOT) Flips the bits of its operand

|

(Bitwise OR) Returns a 1 in a bit if bits of either operand is 1

&

(Bitwise AND) Returns a 1 in each bit position if bits of both operands are 1s

(Bitwise XOR) Returns a 1 in a bit position if bits of one but not both operands are 1

<<

(Left-shift) Shifts its first operand in binary representation the number of bits to the left specified in the second operand, shifting in 0s from the right

>>

(Sign-propagating right-shift) Shifts the first operand in binary representation the number of bits to the right specified in the second operand, discarding bits shifted off

|=

Bitwise OR with result assigned to the first operand

&=

Bitwise AND with result assigned to the first operand

=

Bitwise XOR with result assigned to the first operand

<<=

Left-shift with result assigned to the first operand

>>=

Sign-propagating right-shift with result assigned to the first operand

!

Evaluates the opposite of the value specified

&&

Requires both values to be true for the result to be true

||

Requires only one value to be true for the result to be true

==

Left-hand value and right-hand value are equal

!=

Left-hand value and right-hand value are not equal

<

Left-hand value is less than right-hand value

>

Left-hand value is greater than right-hand value

<=

Left-hand value is less than or equal to right-hand value

>=

Left-hand value is greater than or equal to right-hand value

$=

Left-hand string is equal to right-hand string

!$=

Left-hand string is not equal to right-hand string

//

Comment operator—ignore all text from here to the end of the line

;

Statement terminator

.

Object/data block method or property delimiter

Operators range from the familiar to the mighty weird. The familiar will be the ones like add ("+") and subtract (""). A little strange for those who are adept with standard secondary school math but new to programming languages is the multiplication symbol— an asterisk ("*"). The division symbol, though not the regular handwritten one, is still a somewhat familiar slash ("/"). A mighty weird one would be the vertical pipe ("|"), which is used to perform an OR operation on the bits of a variable.

Some of the operators are probably self-explanatory or understandable from the table. Others may require some explanation, which you will find in the following sections of this chapter.

You'll recall that strings and numbers are treated the same; there is, however, one exception, and that is when comparing strings to strings or numbers to numbers. We use different operators for those comparisons. For number comparisons, we use == (that's not a typo—it's two equal signs in a row; read it as "is identical to") and for string comparisons, we use $= (read it as "string is identical to"). These operators will be discussed more in the sections called "Conditional Expressions" and "Branching."

Operator Precedence

An issue with evaluating expressions is that of order of evaluation. Should %a + %b * %c be evaluated by performing the multiplication first or by performing the addition first? In other words, as %a + (%b * %c) or as (%a + %b) * %c?

Torque and other languages (such as C/C++) solve this problem by assigning priorities to operators; operators with high priority are evaluated before operators with low priority. Operators with equal priority are evaluated in left-to-right order. The priorities of the operators seen so far are, in order of high to low priority, as follows:

 ( ) * / % + = 

Therefore, %a + %b * %c is evaluated as if it had been written as %a + (%b * %c) because multiplication (*) has a higher priority than addition (+). If the + needed to be evaluated first, then parentheses would be used as follows: (%a + %b) * %c.

If you have any doubt, then use extra parentheses to ensure the correct order of evaluation. Note that two arithmetic operators cannot be written in succession.

Increment/Decrement Operators

There are some operations that occur so frequently in assignment statements that Torque has shorthand methods for writing them. One common situation is that of incrementing or decrementing an integer variable. For example,

    %n = %n + 1; // increment by one    %n = %n - 1; // decrement by one 

Torque has an increment operator (++) and a decrement operator (). Thus

    %n++; 

can be used for the increment and

    %n--; 

can be used for the decrement.

The ++ and operators here have been written after the variable they affect; they are called the postincrement and postdecrement operators, respectively. Torque does not have preincrement and predecrement operators (which are written before the variable), as you would find in C/C++.

Totalizers

Totalizers are a variation on the increment and decrement theme. Instead of bumping a value up or down by 1, a totalizer does it with any arbitrary value. For example, a common situation that occurs is an assignment like this:

    %total = %total + %more; 

where a variable is increased by some amount and the result is assigned back to the original variable. This type of assignment can be represented in Torque by the following:

    %total += %more; 

This notation can be used with the other arithmetic operators (+, -, *, /, and %), as you can see in the following:

    %prod = %prod * 10; 

which can be written as this:

    %prod *= 10; 

You can use totalizers in compound assignment statements quite easily as well. Here's an example:

    %x = %x/(%y + 1); 

becomes

    %x /= %y + 1; 

and

    %n = %n % 2; 

becomes

    %n %= 2; 

Be careful on that last one! The percent sign in front of the number 2 is the modulus operator, not a scope prefix. You can tell by the space that separates it from the 2—or in the case of the totalizer example, you can tell by the fact that the percent sign is adjacent to the equal sign on the right. They are certainly subtle differences, so make sure you watch for them if you work in code that uses these constructs.

In all cases, you must be performing these operations on numbers and not strings. That wouldn't make any sense!

Loops

Loops are used for repetitive tasks. We saw an example of a loop being used in the FruitLoopy sample program. This loop was used to step through the available types of fruit. The loop was a bounded one that had a specified start and end, a characteristic built into the loop construct we used, the for loop. The other kind of loop we are going to look at is the while loop.

The while Loop

The following piece of Torque Script demonstrates a while loop. It gets a random number between 0 and 10 from the Torque Engine and then prints it out.

 // ======================================================================== //  WhilingAway.cs // //  This module is a program that demonstrates while loops. It prints //  random values on the screen as long as a condition is satisfied. // // ======================================================================== function main() // --------------------------------------------- //      Entry point for the program. // --------------------------------------------- {    %value = 0;             // initialize %value    while (%value < 7)      // stop looping if %n exceeds 7    {       %value = GetRandom(10);  // get a random number between 0 and 10       print("value="@%value ); // print the result    }                             // now back to the top of the loop                                  // ie. do it all again } 

Save this program as C:\3DGPAi1\book\WhilingAway.cs and run it. Note the output. Now run it again. Note the output again—and the fact that this time it's different. That's the randomness in action, right there. But the part that we are really interested in right now is the fact that as long as the number is less than 7, the program continues to loop.

The general form of a while statement is this:

 while ( condition )         statement 

While the condition is true the statement is executed over and over. Each time the condition is satisfied and the statement is executed is called an iteration. The statement may be a single statement (terminated by a semicolon) or code block (delimited by braces) when you want two or more statements to be executed. Note the following points: It must be possible to evaluate the condition on the first entry to the while statement or it will never be satisfied, and its code will never be executed. This means that all variables used in the condition must have been given values before the while statement is encountered. In the preceding example the variable %value was started at 0 (it was initialized) and it was given a random number between 0 and 10 during each iteration of the loop.

Now you have to make sure that at least one of the variables referenced in the condition can be changed in the statement portion that makes up the body of the loop. If you don't, you could end up stuck in an infinite loop. In the preceding example by making sure that the randomly chosen %value would always eventually cause the condition to fail (10 is greater than 7), we ensure that the loop will stop at some point. In fact, the random number code will return 7, 8, 9, and 10 at some point or other—any one of which will cause the code to break out of the loop.

Here is the important thing about while loops: The condition is evaluated before the loop body statements are executed. If the condition evaluates to false when it is first encountered, then the body is never entered. In the preceding example if we had initialized %value with 10, then no execution of the statements in the body of the while loop would have happened.

And now here's a little exercise for you. Write a program, saving it as C:\3DGPAi1\book\looprint.cs. Make the program print all the integers starting at 0 up to and including 250. That's a lot of numbers! Use a while loop to do it.

The for Loop

When programming, we often need to execute a statement a specific number of times. Consider the following use of a while statement to output the numbers 1 to 10. In this case the integer variable i is used to control the number of times the loop is executed.

   %count = 1;   while (%count <= 10)   {     print("count="@%count);     %count++;   } 

Three distinct operations take place:

  • Initialization. Initializes the control variable %count to 1.

  • Evaluation. Evaluates the value of an expression (%count <= 10).

  • Update. Updates the value of the control variable before executing the loop again (%count++).

The for statement is specially designed for these cases—where a loop is to be executed starting from an initial value and iterates until a control condition is satisfied, meanwhile updating the value of the control variable each time around the loop. It has all three operations rolled up into its principal statement syntax. It's sort of the Swiss army knife of loop statements.

The general form of the for statement is

    for ( initialize ; evaluate ; update )        statement 

which executes the initialize operation when the for statement is first entered. The evaluate operation is then performed on the test expression; if it evaluates to true, then the loop statement is executed for one iteration followed by the update operation. The cycle of test, iterate, update continues until the test expression evaluates to false; control then passes to the next statement in the program.

Functions

Functions save work. Once you've written code to solve a problem, you can roll the code into a function and reuse it whenever you encounter that problem again. You can create functions in a manner that allows you to use the code with different starting parameters and either create some effect or return a value to the code that uses the function.

When solving large problems we often use a divide-and-conquer technique, sometimes called problem decomposition. We break a big problem down into smaller problems that are easier to solve. This is often called the top-down approach. We keep doing this until problems become small enough that a single person can solve them. This top-down approach is essential if the work has to be shared among a team of programmers; each programmer ends up with a specification for a small part of the bigger system that is to be written as a function (or a collection of functions). The programmer can concentrate on the solution of only this one problem and is likely to make fewer errors. The function can then be tested on its own for correctness compared to the design specification.

There are many specialized problem areas, and not every programmer can be proficient in all of them. Many programmers working in scientific applications will frequently use math function routines like sine and cosine but would have no idea how to write the code to actually perform those operations. Likewise, a programmer working in commercial applications might know little about how an efficient sorting routine can be written. A specialist can create such routines and place them in a public library of functions, however, and all programmers can benefit from this expertise by being able to use these efficient and well-tested functions.

In the "Arrays" section earlier in this chapter we calculated a total price and total count of several types of fruit with the FruitLoopy program. Here is that program modified somewhat (okay, modified a lot) to use functions. Take note of how small the main function has become now that so much code is contained within the three new functions.

 // ======================================================================== //  TwotyFruity.cs // //  This program adds up the costs and quantities of selected fruit types //  and outputs the results to the display. This module is a variation //  of the FruitLoopy.cs module designed to demonstrate how to use //  functions. // ======================================================================== function InitializeFruit($numFruitTypes) // ------------------------------------------------------------------------ //      Set the starting values for our fruit arrays, and the type //      indices // //      RETURNS: number of different types of fruit // // ------------------------------------------------------------------------ {    $numTypes = 5; // so we know how many types are in our arrays    $bananaIdx=0; // initialize the values of our index variables    $appleIdx=1;    $orangeIdx=2;    $mangoIdx=3;    $pearIdx=4;    $names[$bananaIdx] = "bananas"; // initialize the fruit name values    $names[$appleIdx] = "apples";    $names[$orangeIdx] = "oranges";    $names[$mangoIdx] = "mangos";    $names[$pearIdx] = "pears";    $cost[$bananaIdx] = 1.15; // initialize the price values    $cost[$appleIdx] = 0.55;    $cost[$orangeIdx] = 0.55;    $cost[$mangoIdx] = 1.90;    $cost[$pearIdx] = 0.68;    $quantity[$bananaIdx] = 1; // initialize the quantity values    $quantity[$appleIdx]  = 3;    $quantity[$orangeIdx] = 4;    $quantity[$mangoIdx]  = 1;    $quantity[$pearIdx]   = 2;    return($numTypes); } function addEmUp($numFruitTypes) // ------------------------------------------------------------------------ //      Add all prices of different fruit types to get a full total cost // //      PARAMETERS: %numTypes -the number of different fruit that are tracked // //      RETURNS: total cost of all fruit // // ------------------------------------------------------------------------ {    %total = 0;    for (%index = 0; %index <= $numFruitTypes; %index++)    {       %total = %total + ($quantity[%index]*$cost[%index]);    }    return %total; } // ------------------------------------------------------------------------ //  countEm // //     Add all quantities of different fruit types to get a full total // //     PARAMETERS: %numTypes -the number of different fruit that are tracked // //     RETURNS: total of all fruit types // // ------------------------------------------------------------------------ function countEm($numFruitTypes) {     %total = 0;     for (%index = 0; %index <= $numFruitTypes; %index++)     {        %total = %total + $quantity[%index];     }     return %total; } function main() // ------------------------------------------------------------------------ //     Entry point for program. This program adds up the costs //     and quantities of selected fruit types and outputs the results to //     the display. This program is a variation of the program FruitLoopy // // ------------------------------------------------------------------------ {    //    // ----------------- Initialization -----------------    //    $numFruitTypes=InitializeFruit(); // set up fruit arrays and variables    %numFruit=0;    // always a good idea to initialize *all* variables!    %totalCost=0;   // (even if we know we are going to change them later)    //    // ----------------- Computation -----------------    //    // Display the known statistics of the fruit collection    for (%index = 0; %index < $numFruitTypes; %index++)    {    print("Cost of " @ $names[%index] @ ":$" @ $cost[%index]);    print("Number of " @ $names[%index] @ ":" @ $quantity[%index]);    }    // count up all the pieces of fruit, and display that result    %numFruit = countEm($numFruitTypes);    print("Total pieces of Fruit:" @ %numFruit);    // now calculate the total cost    %totalCost = addEmUp($numFruitTypes);    print("Total Price of Fruit:$" @ %totalCost); } 

Save this program as C:\3DGPAi1\book\TwotyFruity.cs and run it in the usual way. Now go and run your FruitLoopy program, and compare the output. Hopefully, they will be exactly the same.

In this version all the array initialization has been moved out of the main function and into the new InitializeFruit function. Now, you might notice that I have changed the arrays to be global variables. The reason for this is that Torque does not handle passing arrays to functions in a graceful manner. Well, actually it does, but we would need to use ScriptObjects, which are not covered until a later chapter, so rather than obfuscate things too much right now, I've made the arrays into global variables. This will serve as a useful lesson in contrast between global and local variables anyway, so I thought, why not?

The global arrays can be accessed from within any function in the file. The local ones (with the percent sign prefix), however, can only be accessed within a function. This is more obvious when you look at the addEmUp and countEm functions. Notice that they both use a variable called %total. But they are actually two different variables whose scope does not extend outside the functions where they are used. So don't get mixed up!

Speaking of addEmUp and countEm, these functions have another construct, called a parameter. Sometimes we use the word argument instead, but because we are all friends here, I'll stick with parameter.

Functions with No Parameters

The function main has no parameters, so you can see that parameters are not always required. Because the arrays are global, they can be accessed from within any function, so we don't need to try to pass in the data for them anyway.

Functions with Parameters and No Return Value

Parameters are used to pass information into a function, as witnessed with the functions addEmUp and countEm. In both cases we pass a parameter that tells the function how many types of fruit there are to deal with.

The function declaration looked like this:

 function addEmUp(%numTypes) { 

and when we actually used the function we did this:

  %totalCost = addEmUp($numFruitTypes); 

where $numFruitTypes indicates how many types of fruit there are—in this case, five. This is known as a call to the function addEmUp. We could have written it as

  %totalCost = addEmUp(5); 

but then we would have lost the flexibility of using the variable to hold the value for the number of fruit types.

This activity is called parameter passing. When a parameter is passed during a function call, the value passed into the function is assigned to the variable that is specified in the function declaration. The effect is something like %numTypes = $numFruitTypes;now this code doesn't actually exist anywhere, but operations are performed that have that effect. Thus, %numTypes (inside the function) receives the value of $numFruitTypes (outside the function).

Functions That Return Values

The function InitializeFruit returns a number for the number of different fruit types with this line:

    return(%numTypes); 

and the functions addEmUp and countEm both have this line:

    return %total; 

Notice that the first example has the variable sitting inside some parentheses, and the second example does not. Either way is valid.

Now what happens is that when Torque encounters a return statement in a program, it gathers up the value in the return statement, and then exits the function and resumes execution at the code where the function was called. There isn't always a return statement in a function, so don't be annoyed if you see functions without them. In the case of the InitializeFruit function, that would have been the line near the start of main that looks like this:

    $numFruitTypes=InitializeFruit(); // set up fruit arrays and variables 

If the function call was part of an assignment statement, as above, then whatever value was gathered at the return statement inside the function call is now assigned in the assignment statement. Another way of expressing this concept is to say that the function evaluated to the value of the return statement inside the function.

Return statements don't need to evaluate to anything, however. They can be used to simply stop execution of the function and return control to the calling program code with a return value. Both numbers and strings can be returned from a function.

Conditional Expressions

A conditional or logical expression is an expression that can only evaluate to one of two values: true or false. A simple form of logical expression is the conditional expression, which uses relational operators to construct a statement about a given condition. The following is an example of a conditional expression:

 %x < %y 

(read as %x is less than %y), which evaluates to true if the value of the variable %x is less than the value of the variable %y. The general form of a conditional expression is

 operandA relational_operator operandB 

The operands can be either variables or expressions. If an operand is an expression, then the expression is evaluated and its value used as the operand. The relational operators allowable in Torque are shown in Table 2.5.

Table 2.5: Relational Operators

Symbol

Meaning

<

less than

>

greater than

<=

less than or equal to

>=

greater than or equal to

==

equal to

!=

not equal to

$=

string equal to

!$=

string not equal to

Note

Another name for logic that involves only the values true or false is Boolean logic.

Note that equality is tested for using the operator == because = is already used for assigning values to variables. The condition evaluates to true if the values of the two operands satisfy the relational operator and false if they don't.

Here are some examples:

 %i < 10 %voltage >= 0.0 %total < 1000.0 %count != %n %x * %x + %y * %y < %r * %r 

Depending on the values of the variables involved, each of the preceding expressions is true or false. If %x has the value 3, %y is 6, and %r is 10, the last expression evaluates to true, but if %x was 7 and %y was 8, then it would evaluate to false.

The value of a logical expression can be stored in a variable for later use. Any numerical expression can be used for the value of a condition, with 0 being interpreted as false and 1 as true.

This means that the value a logical expression evaluates to can be used in arithmetical operations. This is often done by programmers, but it is a practice not to be recommended. It can lead to code obscurity, creating a program that is difficult to understand.

Logical Expressions

We can create more complex conditions than those that can be written using only the relational operators described in the preceding section. There are explicit logical operators for combining the logical values true and false.

The simplest logical operator is NOT, which is represented in Torque by the exclamation point ("!"). It operates on a single operand and returns false if its operand is true and true if its operand is false.

The operator AND, represented by two ampersands ("&&"), takes two operands and is true only if both of the operands are true. If either operand is false, the resulting value is false.

The final logical operator is OR, which is represented by two vertical pipes ("||"). It results in true if either operand is true. It returns false only if both its operands are false.

The logical operators can be defined by truth tables as seen in Table 2.6. The "F" character is used for false and "T" is used for true in these tables.

Table 2.6: Logical Operator Truth Tables

NOT

(!)

OR (||)

AND (&&)

A

!A

A

B

A OR B

A

B

A AND B

F

T

T

T

T

T

T

T

T

F

T

F

T

T

F

F

F

T

T

F

T

F

F

F

F

F

F

F

These tables show that NOT reverses the truth value of the operand A; that the AND of two operands is only true if both operands are true; and that the OR of two operands is true if either or both of its operands are true. Now we can write pretty complex logical operations.

If %i has the value 15, and %j has the value 10, then the expression (i > 10) && (j > 0) is evaluated by evaluating the relation i > 10 (which is true), then evaluating the relation %j > 0 (which is also true), to give true. If %j has the value -1, then the second relation would be false, so the overall expression would be false. If i has the value 5, then the first relation would be false, and the expression will be false irrespective of the value of the second relation. Torque does not even evaluate the second relation in this situation. Similarly, if the first relation is true in an OR (||) expression, then the second relation will not be evaluated. This short-circuit evaluation enables many logical expressions to be efficiently evaluated.

Examples Using Logical Operators

Note that in the last example that follows, an actual truth value (0 or false) was used as one of the operands of &&. This means that whatever the value of %i, this logical expression evaluates to false. In these examples parentheses have been used to clarify the order of operator application.

 (%i < 10) && (%j > 0) ((%x + %y) <= 15) || (%i == 5) !((%i >= 10) || (%j <= 0)) (%i < 10) && 0 

You've got to be careful not to confuse the assignment operator = with the logical equality operator ==. Using Table 2.6 with the following expression

 x + y < 10 && x/y == 3 || z != 10 

shows that the operators are evaluated in the order /, +, <, ==, !=, &&, and ||. This is the same as using parentheses on the expression in this way: ((((x + y) < 10) && ((x/y) == 3)) || (z != 10)).

Similarly, the expressions given above could be written without parentheses as follows:

 i < 10 && j > 0 x + y <= 15 || i == 5 !(i >= 10 || j <= 0) i < 10 && 0 

Now that we've covered the logical expressions (or conditions) in Torque, let's move on and take a look at the conditional control mechanisms in Torque.

Branching

The term branching refers to the idea that code can follow different execution paths depending on, well, something. What it depends onummmdepends. Well, let me try that again. It depends on what your program is doing and what you want it to do. Like this: Say you are driving on a road, and you reach a T junction. The sign points left and says "Toronto 50 km." Another sign points right and says "Toronto (Scenic Route) 150 km." Which way are you going to go, left or right? Well, you see? It depends. The fastest way to Toronto might be to go left, but what if you aren't in a hurry—maybe you're interested in the scenic route? Just as we've seen earlier with looping, there are conditions that will dictate what path your code will take.

That act of taking one path over others available is branching. Branching starts out with some sort of decision-making test. In addition to the two looping statements we've already covered—which employ branching of sorts—there are also two branch-specific statements: the if statement and the switch statement.

The if Statement

The simplest way to select the next thing to do in a program based upon conditions is to use the if statement. Check this out:

 if (%n > 0)    print("n is a positive number"); 

This will print out the message n is a positive number only if %n is positive. The general form of the if statement is this:

 if (condition)    statement 

where condition is any valid logical expression as described in the "Conditional Expressions" section we saw earlier.

This if statement adds %something to the variable %sum if %something is positive:

 if (%something > 0)    %sum += %something; 

If %something isn't positive, then the program branches past the totalizer statement, and so %sum doesn't get incremented by %something.

This next piece of code also adds %something to %sum, but it also increments a positive number counter called %poscount:

 if (%something > 0) {    %sum += %something;    %counter++; } 

Note how in the second example a compound statement has been used to carry out more than one operation if the condition is true. If it had been written like this:

 if (%something > 0)   %sum += %something;   %counter++; 

then if %something was greater than 0 the next statement would be executed—that is, %sum would incremented by the amount of %something. But the statement incrementing %counter is now going to be treated as the next statement in the program and not as part of the if statement. The program execution is not going to branch around it. The effect of this would be that %counter would be incremented every time it is encountered, no matter whether %something is positive or negative.

The statements within a compound statement can be any Torque statements. In fact, another if statement could be included. For example, the following code will print a message if a quantity is negative and a further message if no overdraft has been arranged:

 if ( %balance < 0 ) {    print ("Your account is overdrawn. Balance is: " @ %balance );    if ( %overdraft <= 0 )       print ("You have exceeded your overdraft limit"); } 

Now we could have done the same thing using two sequential if statements and more complex conditions:

 if ( %balance < 0 )    print ("Your account is overdrawn. Balance is: " @ %balance ); if ( %balance < 0 && %overdraft <= 0 )       print ("You have exceeded your overdraft limit"); 

You should note that one of these versions will generally execute a little bit faster than the second when dealing with accounts that are not overdrawn. Before I tell you later in this chapter, see if you can figure out which one, and why.

The if-else Statement

A simple if statement only allows a single branch to a simple or compound statement when a condition holds. Sometimes there are alternative paths, some that need to be executed when the condition holds, and some to be executed when the condition does not hold. The two forms can be written this way:

 if (%coffeeholic == true)       print ("I like coffee."); if (%coffeeholic == false)       print ("I don't like coffee."); 

This technique will work while the statements that are executed as a result of the first comparison do not alter the conditions under which the second if statement are executed. Torque provides a direct means of expressing these kinds of choices. The if-else statement specifies statements to be executed for both possible logical values of the condition in an if statement. The following example of an if-else statement writes out one message if the variable %coffeeholic is positive and another message if %coffeeholic is negative:

 if (%coffeeholic == true)       print ("I like coffee."); else       print ("I don't like coffee."); 

The general form of the if-else statement is this:

 if ( condition )    statementA else    statementB 

If the condition is true, then statementA is executed; otherwise statementB is executed. Both statementA and statementB may be either simple or compound statements.

The following if-else statement evaluates if a fruit is fresh or not, and if it is, the statement increments a fresh fruit counter. If the fruit isn't fresh, the statement increments the rotten fruit counter. I'm going to program my refrigerator's fruit crisper to do this one day and send me reports over the Internet. Well, I can wish, can't I?

 if (%fruitState $= "fresh") {    %freshFruitCounter++; } else {    %rottenFruitCounter++; } 

Time for another sample program! Type the following program in and save it as C:\3DGPAi1\book\Geometry.cs and then run it.

 // ======================================================================== //  geometry.cs // //  This program calculates the distance around the perimeter of //  a quadrilateral as well as the area of the quadrilateral and outputs the //  values. It recognizes whether the quadrilateral is a square or a rectangle and //  modifies its output accordingly. Program assumes that all angles in the //  quadrilateral are equal. Demonstrates the if-else statement. // ======================================================================== function calcAndPrint(%theWidth, %theHeight) // ------------------------------------------------------------------------ //    This function does the shape analysis and prints the result. // //    PARAMETERS: %theWidth - horizontal dimension //                 %theHeight - vertical dimension // //    RETURNS: none // ------------------------------------------------------------------------ {    // calculate perimeter    %perimeter = 2 * (%theWidth+%theHeight);    // calculate area    %area = %theWidth * %theHeight;    // first, set up the dimension output string    %prompt = "For a " @ %theWidth @ " by " @                %theHeight @ " quadrilateral, area and perimeter of ";    // analyze the shape's dimensions and select different    // descriptors based on the shape's dimensions    if (%theWidth == %theHeight)                 // if true, then it's a square      %prompt = %prompt @ "square: ";    else                                         // otherwise it's a rectangle    %prompt = %prompt @ "rectangle: ";    // always output the analysis    print (%prompt @ %area @ " " @ %perimeter); } function main() // ------------------------------------------------------------------------ //    Entry point for the program. // ------------------------------------------------------------------------ {    // calculate and output the results for three    // known dimension sets    calcAndPrint(22, 26); // rectangle    calcAndPrint(31, 31); // square    calcAndPrint(47, 98); // rectangle } 

What we've done here is analyze a shape. In addition to printing its calculated measurements, we modify our output string based upon the (simple) analysis that determines if it is a square or a rectangle. I realize that a square is a rectangle, but let's not get too picky, okay? Not yet, at least.

Nesting if Statements

You saw earlier in "The if Statement" section how an if statement can contain another if statement. These are called nested if statements. There is no real limit to how deep you can nest the statements, but try to be reasonable and only do it if it is absolutely necessary for functional reasons. It might be good to do it for performance reasons, and that's fine as well.

By the way, I had asked if you could tell which of the two examples would execute faster, remember that? The answer is that the nested version will execute faster when there is no overdraft condition. This is because only one condition is tested, resulting in less work for the computer to do. The sequential version will always perform both tests, no matter what the bank balance is.

The if and if-else statements allow a choice to be made between two possible alternatives. Well, sometimes we need to choose between more than two alternatives. For example, the following sign function returns 1 if the argument is less than 0, returns +1 if the argument is greater than 0, and returns 0 if the argument is 0.

 function sign (%value) //   determines the arithmetic sign of a value // //   PARAMETERS: %value - the value to be analyzed // //   RETURNS: -1 - if value is negative //              0 - if value is zero //              1 - if value is positive {    if (%value < 0) // is it negative ?    {        return -1;    }    else                    // nope, not negative    {        if (%value == 0) // is it zero ?        {            return 0;        }        else             // nope, then it must be positive        {        return 1;      }    } } 

So there you go. The function has an if-else statement in which the statement following the else is also an if-else statement. If %value is less than 0, then sign returns 1, but if it is not less than 0, the statement following the else is executed. In that case if %value is equal to 0, then sign returns 0; otherwise it returns 1. I used the compound statement form in order to make the nesting stand out more. The nesting could also be written like this:

    if (%value < 0) // is it negative ?       return -1;    else             // nope, not negative       if (%value == 0) // is it zero ?           return 0;       else          // nope, then it must be positive          return 1; 

This is nice and compact, but it can sometimes be hard to discern where the nesting properly happens, and it is easier to make mistakes. Using the compound form formalizes the nesting a bit more, and personally, I find it more readable.

Newbie programmers sometimes use a sequence of if statements rather than nested if-else statements when the latter should be used. They would write the guts of the sign function like this:

    if (%value < 0)        %result = -1;    if (%value == 0)        %result = 0;    if (%value > 0)        %result = 1;        return %result; 

It would work and it's fairly easy to read, but it's inefficient because all three conditions are always tested.

If nesting is carried out to too deep a level and indenting is not consistent, then deeply nested if or if-else statements will be confusing to read and interpret. You should note that an else always belongs to the closest if without an else.

The switch Statement

We just explored how we can choose between more than two possibilities by using nested if-else statements. There is a sleeker and more readable method available for certain kinds of multiple choice situations—the switch statement. For example, the following switch statement will set a game's weapon label based upon a numeric weapon type variable:

 switch (%weaponType) {     case 1: %weaponName = "knife";     case 2: %weaponName = "pistol";     case 3: %weaponName = "shotgun";     case 4: %weaponName = "bfg1000";     default: %weaponName = "fist"; } 

Here is what that would look like using if-else:

 if (%weaponType == 1)    %weaponName = "knife"; else if (%weaponType == 2)    %weaponName = "pistol"; else if (%weaponType == 3)    %weaponName = "shotgun"; else if (%weaponType == 4)    %weaponName = "bfg1000"; else    %weaponName = "fist"; 

It's pretty obvious from that simple example why the switch statement is so useful.

The general form of a switch statement is this:

 switch ( selection-variable ) {        case label1:                    statement1;        case label2:                    statement2;           ...        case labeln:                    statementn;        default:                    statementd; } 

The selection-variable may be a number or a string or an expression that evaluates to a number or a string. The selection-variable is evaluated and compared with each of the case labels. The case labels all have to be different. If a match is found between the selection-variable and one of the case labels, then the statements that follow the matched case until the next case statement will be executed. If the value of the selection-variable can't be matched with any of the case labels, then the statements associated with default are executed. The default is not required but should only be left out if it is certain that the selection-variable will always take the value of one of the case labels.

Here is another example, which writes out the day of the week depending on the value of the number variable %day.

 switch (%day) {     case 1 :                print("Sunday");     case 2 :                print("Monday");     case 3 :                print("Tuesday");     case 4 :                print("Wednesday");     case 5 :                print("Thursday");     case 6 :                print("Friday");     case 7 :                print("Saturday");    default :                print("Not a valid day number"); } 

Debugging and Problem Solving

When you run your programs, the Torque Engine will automatically compile them and output a new .cs.dso file if it needs to. Therefore, geometry.cs (the source code) will become geometry.cs.dso (the compiled code). There is a gotcha though: If the script compiler detects an error in your code, it will abort the compilation, but will not stop the program execution—rather, it will use the existing compiled version if one exists. This is an important point to remember. If you are changing your code, yet you don't see any change in behavior, then you should check the log file in console.log and look for any compile errors.

The log output is pretty verbose and should guide you to the problem area pretty quickly. It writes out a piece of code around the problem area and then inserts a pair of sharp characters ("##") on either side of the exact spot where the compiler thinks there is a problem.

Once you've fixed the first problem, don't assume you are done. Quite often, once one problem is fixed, the compiler marches on through the code and finds another one. The compiler always aborts as soon as it encounters the first problem.

Of the large number of programming errors that the compiler catches and identifies, here are a few specific ones that frequently crop up:

  • Missing semicolon at the end of a statement.

  • Missing a slash in double-slash comment operator.

  • Missing % or $ (scope prefix) from variable names.

  • Using uninitialized variables.

  • Mixing global and local scope prefixes.

  • Unbalanced parentheses or braces.

In a later chapter we will cover how to use the console mode in Torque. That will give us access to three built-in Torque functions—echo, warn, and error—which are quite useful for debugging.

Without using those three functions, the best tool for debugging programs you've created is the print statement. You should print out interim results throughout your code that will tell you how your program is progressing.

Tell you what—here is a different version of the TwotyFruity program. Type it in and save it as C:\3DGPAi1\book\WormyFruit.cs. I've put five bugs in this version. See if you can spot them (in addition to any you might introduce while typing).

 // ======================================================================== //  WormyFruit.cs // //  Buggy version of TwotyFruity. It has five known bugs in it. //  This program adds up the costs and quantities of selected fruit types //  and outputs the results to the display. This module is a variation //  of the FruitLoopy.cs module designed to demonstrate how to use //  functions. //  ======================================================================== function InitializeFruit(%numFruitTypes) // ------------------------------------------------------------------------- //     Set the starting values for our fruit arrays, and the type //     indices // //     RETURNS: number of different types of fruit // // ------------------------------------------------------------------------- {    $numTypes = 5; //  so we know how many types are in our arrays    $bananaIdx=0;    //  initialize the values of our index variables    $appleIdx=1;    $orangeIdx=2;    $mangoIdx=3;    $pearIdx=3;    $names[$bananaIdx] = "bananas"; //  initialize the fruit name values    $names[$appleIdx] = "apples";    $names[$orangeIdx] = "oranges";    $names[$mangoIdx] = "mangos";    $names[$pearIdx] = "pears";    $cost[$bananaIdx] = 1.15; //  initialize the price values    $cost[$appleIdx] = 0.55;    $cost[$orangeIdx] = 0.55;    $cost[$mangoIdx] = 1.90;    $cost[$pearIdx] = 0.68;    $quantity[$bananaIdx] = 1; //  initialize the quantity values    $quantity[$appleIdx] = 3;    $quantity[$orangeIdx] = 4;    $quantity[$mangoIdx] = 1;    $quantity[$pearIdx] = 2;    return(%numTypes); } function addEmUp($numFruitTypes) // ------------------------------------------------------------------------- //     Add all prices of different fruit types to get a full total cost // //     PARAMETERS: %numTypes -the number of different fruit that are tracked // //     RETURNS: total cost of all fruit // // ------------------------------------------------------------------------- {    %total = 0;    for (%index = 0; %index <= $numFruitTypes; %index++)    {       %total = %total + ($quantity[%index]*$cost[%index]);    }    return %total; } // ------------------------------------------------------------------------- //  countEm // //     Add all quantities of different fruit types to get a full total // //     PARAMETERS: %numTypes -the number of different fruit that are tracked // //     RETURNS: total of all fruit types // // ------------------------------------------------------------------------- function countEm($numFruitTypes) {    %total = 0;    for (%index = 0; %index <= $numFruitTypes; %index++)    {       %total = %total + $quantity[%index];    } } function main() // ------------------------------------------------------------------------- //     Entry point for program. This program adds up the costs //     and quantities of selected fruit types and outputs the results to //     the display. This program is a variation of the program FruitLoopy // // ------------------------------------------------------------------------- {    //    //  ----------------- Initialization ---------------------    //    $numFruitTypes=InitializeFruit(); //  set up fruit arrays and variables    %numFruit=0     //  always a good idea to initialize *all* variables!    %totalCost=0;   //  (even if we know we are going to change them later)    //    //  ----------------- Computation ---------------------    //    //  Display the known statistics of the fruit collection    for (%index = 0; %index < $numFruitTypes; %index++)    {    print("Cost of " @ $names[%index] @ ":$" @ $cost[%index]);    print("Number of " @ $names[%index] @ ":" @ $quantity[%index]);    }    //  count up all the pieces of fruit, and display that result    %numFruit = countEm($numFruitTypes));    print("Total pieces of Fruit:" @ %numFruit);    //  now calculate the total cost    %totalCost = addEmUp($numFruitTypes);    print("Total Price of Fruit:$" @ %totalCost); } 

Run the program, and use the original TwotyFruity output as a specification to tell you whether or not this program is working correctly.

Best Practices

Programming is as much an art as it is anything else. There are often quite strenuous discussions between programmers about the best way to do certain things. However, there is consensus on a few practices that are considered to be good.

So take the following list as a guideline, and develop a style that is comfortable for you.

  • Use module and function header comments to document your code.

  • Sprinkle lots of commentary through your code, and make sure that it actually explains what is happening.

  • Don't comment obvious things. Save the effort for the stuff that matters.

  • Use white space (blank lines and spaces) to improve readability.

  • Indent your code with readability in mind.

  • Decompose large problems into small ones, and assault the small problems with functions.

  • Organize your code into separate modules, and make sure the module file name is appropriate for the content, and vice versa.

  • Restrict the number of lines of code you put in a module. Pick a size that suits you—about 1,000 lines should be near your upper limit.

  • Use descriptive and meaningful variable names.

  • While keeping your variable names descriptive, don't let the names get too long.

  • Never embed tabs in code—use spaces instead. When you view your code later, you may have different tab settings, and therefore find the code hard to read. Using spaces guarantees that the visual appearance is consistent. Three spaces for an indent is a good number.

  • Be consistent in your programming style decisions.

  • Be alert to what programming decisions you make that work well for you, and try to consistently employ those techniques.

  • Keep a change log of your work so you can keep track of the evolution of your programs.

  • Use revision control software to manage your program versions.




3D Game Programming All in One
3D Game Programming All in One (Course Technology PTR Game Development Series)
ISBN: 159200136X
EAN: 2147483647
Year: 2006
Pages: 197

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net