- •Microsoft C# Programming for the Absolute Beginner
- •Table of Contents
- •Microsoft C# Programming for the Absolute Beginner
- •Introduction
- •Overview
- •Chapter 1: Basic Input and Output: A Mini Adventure
- •Project: The Mini Adventure
- •Reviewing Basic C# Concepts
- •Namespaces
- •Classes
- •Methods
- •Statements
- •The Console Object
- •.NET Documentation
- •Getting into the Visual Studio .Net Environment
- •Examining the Default Code
- •Creating a Custom Namespace
- •Adding Summary Comments
- •Creating the Class
- •Moving from Code to a Program
- •Compiling Your Program
- •Looking for Bugs
- •Getting Input from the User
- •Creating a String Variable
- •Getting a Value with the Console.ReadLine() Method
- •Incorporating a Variable in Output
- •Combining String Values
- •Combining Strings with Concatenation
- •Adding a Tab Character
- •Using the Newline Sequence
- •Displaying a Backslash
- •Displaying Quotation Marks
- •Launching the Mini Adventure
- •Planning the Story
- •Creating the Variables
- •Getting Values from the User
- •Writing the Output
- •Finishing the Program
- •Summary
- •Chapter 2: Branching and Operators: The Math Game
- •The Math Game
- •Using Numeric Variables
- •The Simple Math Game
- •Numeric Variable Types
- •Integer Variables
- •Long Integers
- •Data Type Problems
- •Math Operators
- •Converting Variables
- •Explicit Casting
- •The Convert Object
- •Creating a Branch in Program Logic
- •The Hi Bill Game
- •Condition Testing
- •The If Statement
- •The Else Clause
- •Multiple Conditions
- •Working with The Switch Statement
- •The Switch Demo Program
- •Examining How Switch Statements Work
- •Creating a Random Number
- •Introducing the Die Roller
- •Exploring the Random Object
- •Creating a Random Double with the .NextDouble() Method
- •Getting the Values of Dice
- •Creating the Math Game
- •Designing the Game
- •Creating the Variables
- •Managing Addition
- •Managing Subtraction
- •Managing Multiplication and Division
- •Checking the Answers
- •Waiting for the Carriage Return
- •Summary
- •Chapter 3: Loops and Strings: The Pig Latin Program
- •Project: The Pig Latin Program
- •Investigating The String Object
- •The String Mangler Program
- •A Closer Look at Strings
- •Using the Object Browser
- •Experimenting with String Methods
- •Performing Common String Manipulations
- •Using a For Loop
- •Examining The Bean Counter Program
- •Creating a Sentry Variable
- •Checking for an Upper Limit
- •Incrementing the Variable
- •Examining the Behavior of the For Loop
- •The Fancy Beans Program
- •Skipping Numbers
- •Counting Backwards
- •Using a Foreach Loop to Break Up a Sentence
- •Using a While Loop
- •The Magic Word Program
- •Writing an Effective While Loop
- •Planning Your Program with the STAIR Process
- •S: State the Problem
- •T: Tool Identification
- •A: Algorithm
- •I: Implementation
- •R: Refinement
- •Applying STAIR to the Pig Latin Program
- •Stating the Problem
- •Identifying the Tools
- •Creating the Algorithm
- •Implementing and Refining
- •Writing the Pig Latin Program
- •Setting Up the Variables
- •Creating the Outside Loop
- •Dividing the Phrase into Words
- •Extracting the First Character
- •Checking for a Vowel
- •Adding Debugging Code
- •Closing Up the code
- •Summary
- •Introducing the Critter Program
- •Creating Methods to Reuse Code
- •The Song Program
- •Building the Main() Method
- •Creating a Simple Method
- •Adding a Parameter
- •Returning a Value
- •Creating a Menu
- •Creating a Main Loop
- •Creating the Sentry Variable
- •Calling a Method
- •Working with the Results
- •Writing the showMenu() Method
- •Getting Input from the User
- •Handling Exceptions
- •Returning a Value
- •Creating a New Object with the CritterName Program
- •Creating the Basic Critter
- •Using Scope Modifiers
- •Using a Public Instance Variable
- •Creating an Instance of the Critter
- •Adding a Method
- •Creating the talk() Method for the CritterTalk Program
- •Changing the Menu to Use the talk() Method
- •Creating a Property in the CritterProp Program
- •Examining the Critter Prop Program
- •Creating the Critter with a Name Property
- •Using Properties as Filters
- •Making the Critter More Lifelike
- •Adding More Private Variables
- •Adding the Age() Method
- •Adding the Eat() Method
- •Adding the Play() Method
- •Modifying the Talk() Method
- •Making Changes in the Main Class
- •Summary
- •Introducing the Snowball Fight
- •Inheritance and Encapsulation
- •Creating a Constructor
- •Adding a Constructor to the Critter Class
- •Creating the CritViewer Class
- •Reviewing the Static Keyword
- •Calling a Constructor from the Main() Method
- •Working with Multiple Files
- •Overloading Constructors
- •Viewing the Improved Critter Class
- •Adding Polymorphism to Your Objects
- •Modifying the Critter Viewer in CritOver to Demonstrate Overloaded Constructors
- •Using Inheritance to Make New Classes
- •Creating a Class to View the Clone
- •Creating the Critter Class
- •Improving an Existing Class
- •Introducing the Glitter Critter
- •Adding Methods to a New Class
- •Changing the Critter Viewer Again
- •Creating the Snowball Fight
- •Building the Fighter
- •Building the Robot Fighter
- •Creating the Main Menu Class
- •Summary
- •Overview
- •Introducing the Visual Critter
- •Thinking Like a GUI Programmer
- •Creating a Graphical User Interface (GUI)
- •Examining the Code of a Windows Program
- •Adding New Namespaces
- •Creating the Form Object
- •Creating a Destructor
- •Creating the Components
- •Setting Component Properties
- •Setting Up the Form
- •Writing the Main() Method
- •Creating an Interactive Program
- •Responding to a Simple Event
- •Creating and Adding the Components
- •Adding an Event to the Program
- •Creating an Event Handler
- •Allowing for Multiple Selections
- •Choosing a Font with Selection Controls
- •Creating the User Interface
- •Examining Selection Tools
- •Creating Instance Variables in the Font Chooser
- •Writing the AssignFont() Method
- •Writing the Event Handlers
- •Working with Images and Scroll Bars
- •Setting Up the Picture Box
- •Adding a Scroll Bar
- •Revisiting the Visual Critter
- •Designing the Program
- •Determining the Necessary Tools
- •Designing the Form
- •Writing the Code
- •Summary
- •Chapter 7: Timers and Animation: The Lunar Lander
- •Introducing the Lunar Lander
- •Reading Values from the Keyboard
- •Introducing the Key Reader Program
- •Setting Up the Key Reader Program
- •Coding the KeyPress Event
- •Coding the KeyDown Event
- •Determining Which Key Was Pressed
- •Animating Images
- •Introducing the ImageList Control
- •Setting Up an Image List
- •Looking at the Image Collection
- •Displaying an Image from the Image List
- •Using a Timer to Automate Animation
- •Introducing the Timer Control
- •Configuring the Timer
- •Adding Motion
- •Checking for Keyboard Input
- •Working with the Location Property
- •Detecting Collisions between Objects
- •Coding the Crasher Program
- •Getting Values for newX and newY
- •Bouncing the Ball off the Sides
- •Checking for Collisions
- •Extracting a Rectangle from a Component
- •Getting More from the MessageBox Object
- •Introducing the MsgDemo Program
- •Retrieving Values from the MessageBox
- •Coding the Lunar Lander
- •The Visual Design
- •The Constructor
- •The timer1_Tick() Method
- •The moveShip() Method
- •The checkLanding() Method
- •The theForm_KeyDown() Method
- •The showStats() Method
- •The killShip() Method
- •The initGame() Method
- •Summary
- •Chapter 8: Arrays: The Soccer Game
- •The Soccer Game
- •Introducing Arrays
- •Exploring the Counter Program
- •Creating an Array of Strings
- •Referring to Elements in an Array
- •Working with Arrays
- •Using the Array Demo Program to Explore Arrays
- •Building the Languages Array
- •Sorting the Array
- •Designing the Soccer Game
- •Solving a Subset of the Problem
- •Adding Percentages for the Other Players
- •Setting Up the Shot Demo Program
- •Setting Up the List Boxes
- •Using a Custom Event Handler
- •Writing the changeStatus() Method
- •Kicking the Ball
- •Designing Programs by Hand
- •Examining the Form by Hand Program
- •Adding Components in the Constructor
- •Responding to the Button Event
- •Building the Soccer Program
- •Setting Up the Variables
- •Examining the Constructor
- •Setting Up the Players
- •Setting Up the Opponents
- •Setting Up the Goalies
- •Responding to Player Clicks
- •Handling Good Shots
- •Handling Bad Shots
- •Setting a New Current Player
- •Handling the Passage of Time
- •Updating the Score
- •Summary
- •Chapter 9: File Handling: The Adventure Kit
- •Introducing the Adventure Kit
- •Viewing the Main Screen
- •Loading an Adventure
- •Playing an Adventure
- •Creating an Adventure
- •Reading and Writing Text Files
- •Exploring the File IO Program
- •Importing the IO Namespace
- •Writing to a Stream
- •Reading from a Stream
- •Creating Menus
- •Exploring the Menu Demo Program
- •Adding a MainMenu Object
- •Adding a Submenu
- •Setting Up the Properties of Menu Items
- •Writing Event Code for Menus
- •Using Dialog Boxes to Enhance Your Programs
- •Exploring the Dialog Demo Program
- •Adding Standard Dialogs to Your Form
- •Using the File Dialog Controls
- •Responding to File Dialog Events
- •Using the Font Dialog Control
- •Using the Color Dialog Control
- •Storing Entire Objects with Serialization
- •Exploring the Serialization Demo Program
- •Creating the Contact Class
- •Referencing the Serializable Namespace
- •Storing a Class
- •Retrieving a Class
- •Returning to the Adventure Kit Program
- •Examining the Room Class
- •Creating the Dungeon Class
- •Writing the Game Class
- •Writing the Editor Class
- •Writing the MainForm Class
- •Summary
- •Chapter 10: Chapter Basic XML: The Quiz Maker
- •Introducing the Quiz Maker Game
- •Taking a Quiz
- •Creating and Editing Quizzes
- •Investigating XML
- •Defining XML
- •Creating an XML Document in .NET
- •Creating an XML Schema for Your Language
- •Investigating the .NET View of XML
- •Exploring the XmlNode Class
- •Exploring the XmlDocument Class
- •Reading an Existing XML Document
- •Creating the XML Viewer Program
- •Writing New Values to an XML Document
- •Building the Document Structure
- •Adding an Element to the Document
- •Displaying the XML Code
- •Examining the Quizzer Program
- •Building the Main Form
- •Writing the Quiz Form
- •Writing the Editor Form
- •Summary
- •Overview
- •Introducing the SpyMaster Program
- •Creating a Simple Database
- •Accessing the Data Server
- •Accessing the Data in a Program
- •Using Queries to Modify Data Results
- •Limiting Data with the SELECT Statement
- •Using an Existing Database
- •Adding the Capability to Display Queries
- •Creating a Visual Query Builder
- •Working with Relational Databases
- •Improving Your Data with Normalization
- •Using a Join to Connect Two Tables
- •Creating a View
- •Referring to a View in a Program
- •Incorporating the Agent Specialty Attribute
- •Working with Other Databases
- •Creating a New Connection
- •Converting a Data Set to XML
- •Reading from XML to a Data Source
- •Creating the SpyMaster Database
- •Building the Main Form
- •Editing the Assignments
- •Editing the Specialties
- •Viewing the Agents
- •Editing the Agent Data
- •Summary
- •List of Figures
- •List of Tables
- •List of Sidebars
Figure 8.9: When the user clicks the forEach button, the elements of the array are shown one at a time.
Wanting to step through the elements of an array one at a time is common. Arrays and for loops are a natural combination because doing something to each element of an array one at a time is so common. Although you can use a for loop for this purpose, the foreach loop makes examining an array, element by element, even easier to do.
private void btnForEach_Click(object sender, System.EventArgs e) {
//demonstrates the foreach loop used with arrays foreach (string theLang in languages){
MessageBox.Show(theLang);
} // end foreach
}// end btnFor
The foreach loop is a special variant of the for loop. It requires a local variable of the same type as the array and the array name. In this case, theLang is a string that holds each value in the array. Because it’s a string array, theLang must be a string value. The variable name must be followed by the keyword in, followed by the name of the array. The loop occurs once for each element of the array. Each time through the loop, theLang has a different value picked from the array.
Trick The reason this works in the Pig Latin game is this: When I used the Split() method on a string variable, it converted that variable to an array of strings. I could then use the foreach loop to step easily through that array. Closure at last…
Creating Tables with Two−Dimensional Arrays
The type of array you’ve seen so far in this chapter is used whenever you need to work with a list of data. Sometimes, however, you are more interested in more complex information. When you solve complex problems without a computer, you often find yourself keeping information in two−dimensional tables. C# supports a special two−dimensional array that allows you to work with this kind of information.
Designing the Soccer Game
The Soccer program you saw at the beginning of this chapter relies on a table. If you analyze the Soccer program, you will see that all the action revolves around the user's clicking the various players. Somehow the computer has to know the likelihood that a pass from one player to another will succeed. Figure 8.10 shows a program that illustrates the likelihood of any one player's passing to another.
214
Figure 8.10: The halfback should complete a pass to the wing 80 percent of the time. Hint Usually I use the terms player and user interchangeably, but in this chapter, I
have decided to use these terms more carefully. The soccer game has entities called players, and I have chosen to use that term only when I’m referring to these elements inside the game. I use the term user to describe the person playing the game.
Because this is the most critical part of the Soccer game that concludes this chapter, you should learn the basic concepts in a simpler program first, such as the Shot Demo illustrated in Figure 8.10.
As you can see in the Shot Demo program, the user can select one player to kick the ball and one player (or shot) as the target. Whenever the user makes a selection in one of the list boxes, the percentage likelihood this shot will succeed is displayed. The user can then press the kick button, which will succeed at the indicated percentage, to get a feel for how often the indicated percentage succeeds.
Solving a Subset of the Problem
One way to set this up would be to think about a certain player at first. For example, take the fullback, who generally stays near his own goal in a defensive position. It is very likely that the fullback will complete a pass to the goalie or halfback, because these two players are usually in close proximity. It is less likely that the fullback will complete a pass directly to the wing or center and highly unlikely that an attempt on the opponent’s goal will succeed from the fullback’s position. You could encode this information in a simple chart like Table 8.1.
Table 8.1: The Likelihood of Success from the Fullback Spot
Goalie |
Halfback |
Wing |
Center |
Shot |
80% |
80% |
60% |
40% |
2% |
Table 8.1 summarizes the chances of success for a shot or pass from the fullback to other members of the team (or the opposing goal). Although there is absolutely nothing scientific about these values, they are an approximation of the options facing a fullback during a soccer game. Having percentages is nice from a programming point of view because generating a random value that will approximate any percentage is very easy. For example, if you want to set up a condition that will be
215
true 60 percent of the time (to simulate a pass from the fullback to the wing), you could use something like this:
Random roller = new Random(); if (roller.nextDouble() < .6){
MessageBox("Good!");
}else {
MessageBox("No good.");
}// end if
The nextDouble() method produces a random number between 0 and 1. That value will be less than 0.6 about 60 percent of the time. If you have percentages for the likelihood of various situations, writing conditional statements to test whether those situations occur is easy.
Adding Percentages for the Other Players
It would be possible to encapsulate all the information about the fullback’s options in a normal array, but sometimes other players have the ball, too. You can build a more complex table that tries to show all the possible choices in the game. Table 8.2 illustrates one such chart.
Table 8.2: Percentages For All Plays
Kicker |
Goalie |
Fullback |
Halfback |
Wing |
Center |
Goal |
Goalie |
–1 |
.8 |
.6 |
.4 |
.1 |
.01 |
Fullback |
.8 |
–1 |
.8 |
.6 |
.4 |
.02 |
Halfback |
.8 |
.8 |
–1 |
.8 |
.6 |
.03 |
Wing |
.8 |
.8 |
.8 |
–1 |
.8 |
.04 |
Center |
.8 |
.8 |
.8 |
.8 |
–1 |
.2 |
Table 8.2 extends Table 8.1 to consider the likelihood of every opportunity offered to the player during the Soccer game. In this table, the percentages are written as double values (so 80% is written as .8, for example). Also, I used a –1 to indicate an impossible shot. I wanted to require the user to keep moving the ball around the field so that if he attempts to pass from a player to that same player, it will always fail (and in the final game, the opposing team will get a chance to score).
There is absolutely nothing scientific about the percentages I chose. I pulled them completely out of the air as a starting point. When the mechanics of the game are working, it will probably be necessary to tweak the values in this table.
Setting Up the Shot Demo Program
The Shot Demo program uses a special form of array to duplicate the information from Table 8.2 in the computer’s memory. The class−level code includes a new type of array to hold the data:
double chance = 0d;
private double[,] shotChance = { {−1, .8, .6, .4, .1, .01}, {.8, −1, .8, .6, .4, .02}, {.8, .8, −1, .8, .6, .03}, {.8, .8, .8, −1, .8, .04}, {.8, .8, .8, .8, −1, .2},
};
216
Because the program uses percentages extensively, the double type is used to handle all percentage values. The player’s likelihood of succeeding at a shot is stored in the chance variable. The shotChance is an array of doubles. However, you can see that its structure is fundamentally different from the other arrays you’ve seen so far. The data I’m trying to encapsulate in shotDemo comes from a two−dimensional table, so I store it in a two−dimensional array. You set up an array to have two (or more) dimensions by adding a comma (or more) to the brackets that follow the array type. You can predefine the values of the array if you know what the array will contain when you are initializing it. Each row is enclosed in braces, and the entire structure is enclosed in another set of braces. The rows, just like the data inside the rows, are separated by commas.
You can also set up the array without initializing it. If you wanted to make a 3−by−4 double array, for example, you could use a line such as
private double[,] myArray = new double[3,4];
When you have a two−dimensional array, you refer to it using two indices. For example, shotChance[3,2] refers to the third column, second row of the shotChance array, which is the value
.8. (Don’t forget that the computer starts counting with 0, so the third column is what people would consider the fourth column.)
In the Real World
Beginning programmers almost never use an array in this situation. Instead, they shy away from data structures and look at a solution that uses control structures. This is usually a mistake. It would be possible to use a series of if−elseif−endif statements or a nested switch structure to get the same behavior as the array technique I’ll show you here, but that technique would require between 75 and 100 lines of code. A lot of repeated code means many places where things can go wrong and a major headache if you find that you need to tweak your logic. By taking the time to think carefully about a data structure, the 75 lines of code can be shrunk to 4. It’s an amazing improvement in efficiency, and those four lines of code are easier to fix and modify. Experienced programmers often look for control structures that are more complex in the short run but pay off in code complexity for the long run.
Hint There’s no reason to stop at two dimensions. It’s possible to build arrays with four, five, or as many dimensions as you like. Usually, programmers don’t need to make arrays much larger than three dimensions because they can store objects in the arrays, which allow for even more complex and flexible data.
Setting Up the List Boxes
The user will use the list boxes to control the program, so setting them up properly is very important. In particular, the elements in the lists must go in the correct order. The lstKicker list box represents all the various kickers. Each player can be a kicker, but not the opponent’s goal (it is strictly a target), so the list box is filled with the names of the positions. I took special care to associate the names with the rows of the original table (Goalie, Fullback, Halfback, Wing, and Center). The lstTarget list box contains all the various targets. Each player position is a potential target, as is the opposing goal, so this list box has six elements, corresponding to the columns in the original table.
To ensure that the list boxes would begin with legal values, I added code to the constructor to initialize the list boxes:
lstKicker.SelectedIndex = 0;
217