Development environment



Chapter 8: Arrays and issues in automating a real-world application

This chapter will continue the study of arrays. Arrays are an important way of structuring information and provided in most programming languages. The application featured in this chapter brings several general issues of program development into discussion: automating a real-world application, testing and scaling-up. In this chapter, you will

• learn about arrays and collections

• gain experience using loops to manipulate array elements

• acquire appreciation of what may be required for a computer implementation of an application, specifically when it is necessary to program a pause

• learn favorable ways to test an application

• get practice using JavaScript arrays, the image collection of the Document Object Model for HTML documents, JavaScript for-loops, and functions setting up timed events.

Motivating Example

NOTE: The motivating example for this chapter, as with the others, is a game. You may question our calling this a 'real-world application', but it is. People, your potential audience of users, have ideas about how this application works in 'real-life', away from computers. When you attempt to produce a computer version of such an application, you need to be aware of these aspects of the application. Similarly, you need to be aware of people's experiences with other computer applications. All these factors must be considered when designing and building applications.

The game Memory, also called concentration, typically is played with a set of cards consisting of some number of pairs of matching cards. Figure 1 shows the opening screen for a Memory game using a small deck of cards. The hyperlink to shuffle the cards may be removed for the final version of the game.

[pic]

Figure 1. Opening screen for Memory game.

The player clicks on one and then a second of the rectangles.

[pic]

Figure 2. Screen shot after player moves.

The display shown in Figure 2 will only remain on the screen for a short time before the original screen reappears. This simulates the cards being flipped back. Of course, there are no cards, just image files assigned to specified positions.

If the player clicks on two cards assigned to the same image, that is, a matched pair, then these images remain visible as shown in Figure 3.

[pic]

Figure 3. Player finds a match.

You will read about how to implement this game and then how to take steps to implement a larger, improved version.

The critical features required for this application include

• a way to represent the game board, namely the cards as images that can change back and forth between an image representing the common card back and images representing the card face

• a way for clicking on the card to invoke a function

• variables representing the state of the game so that the function can distinguish first turn and second turn and, upon the second turn, compare the two card faces

• a way to simulate shuffling of the cards

• a way to insert a pause so that the player has time to study the card faces

• a way to determine when the game is over. There is no way in the basic game for the player to lose, but it is necessary to determine when the player has won by matching all the pairs of cards.

• a way to prevent a player from clicking on more than two cards. Since there will be a pause after clicking on the second card, a fast player could keep clicking to reveal more card faces.

Introduction to concepts

An array is an aggregation of data. Most programming languages provide arrays, though, as always, the details differ. Arrays allow you, the programmer, to represent sets of values, which eases the implementation of applications that involve sets of things. The code to reference a member of the set makes use of an index value or a key value. A challenge is to not confuse the index or key value with the contents of the array member for that index or key value.

Repeating a sequence of statements, looping, is a common requirement for programming. You may know the number of times you need a sequence of statements to be repeated or it may depend on the value of a variable. Looping is especially useful when manipulating arrays.

The computer implementation of a manual task, a task done 'by hand' in the real-world, can require extra or different steps to work at all or to work in an efficient way. This will be discussed in a general way and then illustrated with the game of Memory.

Testing a program, making sure the application works as required, can take as long as the initial coding. There are ways to make testing easier.

Description: arrays and collections

You have seen JavaScript and ActionScript arrays in previous examples. These were each the simplest type of array: sequences of values, all of the same datatype, with the individual members accessible by index values, numbers going from 0 to 1 less than the number of elements in the array. Assuming the example from Chapter 6,

var options=new Array();

options[0] = "rock";

options[1] = "paper";

options[2] = "scissors";

then the assignment statement

played = options[1];

would assign "paper" to the variable played.

More typically, the index value in an expression involving an array would not be a constant, but a variable.

played = options[answer];

would be interpreted as follows by the language processor:

locate the variable options, confirm that it is an array and determine the length in order to know what are allowable index values (what are the array bounds)

locate the variable answer and extract its value

confirm if the value is an integer within the array bounds

assuming everything is confirmed okay, extract the indicated element of the array

Figure 4 shows two variables, answer and options, with actual contents for the elements of options and n indicating that answer holds something, but exactly what is not known.

[pic]

Figure 4. Schematic for array and index variable.

You can think of the variable answer as a pointer into the array. Figure 5 shows this.

[pic]

Figure 5. Schematic showing variable pointing to array element.

Languages differ in what happens when a value is used as an array index that is not within bounds of the array. This could be a number that is too small (less than zero), too big, or a value that is not a number at all.

TECHNICAL NOTE: C++ does not do run-time checking on array bounds! This means that if the value of answer was greater than 2, something would be assigned to played, but not what was intended. Similarly, if the assignment statement was

options[answer] = played;

and answer held an incorrect value, then the value of played would be plopped down in an incorrect location. One of the advantages many see in Java over C++ is the run-time checking on array bounds. You do need to realize that this feature comes with a cost: the run-time check does take time.

END OF TECHNICAL NOTE

The behavior of JavaScript is complex with respect to assignments to a position in an array using an index value that is out-of-bounds. If answer held an integer value, say 4; played held the string "dirt"; and the assignment statement

options[answer] = played;

was executed, then the value held by the options array would be

"rock", "paper", "scissors", , "dirt"

meaning that the item at the 3rd position was undefined, but the 4th position was the string "dirt". JavaScript creates and sets the new element.

An assignment statement

played = options[answer];

would not trigger an error, but later use of the variable played might cause an error since it has value undefined.

As you would expect, strongly-typed languages require array variables to be declared. Some languages fix the size of the array at declaration time and some allow the array to grow or shrink in size. Some languages allow flexibility for the ranges of index values: they do not have to be 0 to 1 less than the number of items in the array. For example, in certain languages, the index values could be set to be 2000 to 2005 for a problem involving data stored by the year.

TECHNICAL NOTE: Arrays can be more complex. Some programming languages support arrays in which the elements are not all the same datatype. Some programming languages support multi-dimensional arrays directly. Others provide this feature by allowing one-dimensional arrays in which the elements are themselves arrays.

An associative array holds elements accessible by keys. A key can be any value type. A standard example is a set of values, each associated with a day of the week. The keys are strings spelling out the days. If the associative array is classes, then

classes['Monday']

would show information about Monday classes. If the variable currentday held a string indicating one of the days of the week, then

classes[currentday]

would show information for that day.

Now you may be saying that this is nice, but it would not be that much trouble to encode the days of the weeks as numbers. This is, in fact, what the Date class does. Associative arrays provide an alternative approach.

OTHER LANGUAGE NOTE: Associative arrays also can be used when the keys are not known ahead of time. For example, here is an example from php, a language for server-side programming. In php, variable names start with a dollar sign. Assume that $cart is to hold information on what someone has ordered, $product holds the code for the product being ordered and $quantity holds the quantity, then

$cart[$product] = $quantity

would be used to add the order of $qty of $product. The key/value pair, $product/$quantity, has been added to the associative array $cart.

END OF OTHER LANGUAGE NOTE

The Document Object Model that defines how to write code relating to an HTML document specifies several collections, sets of elements with the same name and similar structure. The images collection can be used like an array to reference and set the attributes of tags.

TECHNICAL NOTE: You can read the full specification of the DOM at .

EXAMPLE: A common technique in programming is to use parallel structures to represent aspects of an application. For example, two arrays can hold information in which the ith element of one corresponds to the ith element of the other. In the Memory game featured in the chapter, an array named faces holds the file names of images that are to be displayed in the corresponding member of the document.images collection.

Description: looping

Looping was an early addition to programming languages. Abstractly, a loop specifies a starting value for the loop or index variable, a condition that determines if the body of the loop is to be executed, and a changing operation for the loop variable. This last operation can be called the incrementing step, but it need not be restricted to adding to the loop variable. The loop variable may be used inside the body of the loop or not. In JavaScript and ActionScript, the for-loop follows the concise syntax of C++ and Java. Any variable can be used, but following a convention established with Fortran many years ago, the name you will see most frequently is i. Assuming that start and last are numbers, the code

for (i=start; i $qty) {



}

The body of the loop would be repeated for each key/value pair in the array. In the body, the code would reference the key as $pid and the value as $qty.

END OF OTHER LANGUAGE NOTE

EXAMPLE: The Memory application uses looping for shuffling the cards.

Description: array operations: push, pop, and slice

There are multiple ways to assign values to an array variable. In JavaScript, the statement

var models = new Array();

defines models to be an array variable, but does not assign a value to the variable. You can assign the whole array or assign values to elements of the array as was shown previously in the options example.

An array variable can be set up with values in the declaration statement.

var models = [

"heart",

"crane",

"frogface"

]

TIP: The multiple lines used in the declaration of models makes it easy to add new elements. However, you still need to be careful to put commas after each entry except the last one.

Another technique for adding elements to an array is to use the push method. Assuming that models is still the array with 3 elements as declared and initialized in the previous code, the statement

models.push("box");

will add an element to the end of the variable. Think of a stack of dishes in a cafeteria and you are pushing an item at the top of the stack. The models array is now

["heart", "crane", "frogface", "box"]

The pop method performs two tasks. It removes the last element from the array and returns that value. So after the statement

last = models.pop();

is executed, the variable last has the value "box" and models is back to being

["heart", "crane", "frogface"]

TECHNICAL TIP: The push and pop operations are called LAST-IN/ FIRST OUT processing, also known as stack processing.

The splice method combines removing and adding elements to an array. The name is intended to invoke the action of cutting something out and grafting something in its place. The method has 2 or more parameters. The first parameter indicates the position where the splicing is to start; the second parameter is the number of elements to be removed. The splice method can have 1 or more optional parameters after these first 2. These parameters are values to be added, spliced, into the array.

Assuming the models array is

["heart", "crane", "frogface", "box"]

the models.splice(1,2) will change the array to be

["heart", "box"]

Following this with models(0,1,"bird","fox","purse");

will make the variable be

["bird", "fox", "purse", "box"]

Description: computer versus real-world version of an application

When automating a task or application that exists in a manual version, one strategy is to take the manual way as a model and implement each step. This may or may not work and, if it does work, it may not produce the best results.

EXAMPLE: When people play the Memory game that is the featured example of this chapter, a player turns over one card and then another to reveal the faces. If the cards match, the player takes them off the board. If the cards do not match, the player flips them both over so the cards are face down again. One implementation of the game would require the player to use the mouse to choose the cards and then touch the cards again to restore them to the face down position. Most people would suggest letting ‘the computer’ handle the flipping over or taking away as appropriate. This computer version differs from the original game: the tasks of the player have changed. The tasks are similar to other computer games.

However, there is one additional issue for the game builder to address. The computer implementation needs to include a step that the real-world game did not have: the program must enforce a pause to make sure the player sees the unmatched cards. If a pause is not inserted into the program, the player would not see the second card. Putting in a pause will require setting up a timed event.

END OF EXAMPLE

Making the design of a computer program resemble how a person would do the task manually may be committing an anthropomorphic error. An especially vivid example relates to washing clothes. Think about how people once brought their clothes to a river and pounded the clothes with rocks. You can imagine building an apparatus resembling this scene. This is not the design of a washing machine! Remind yourself of this example when designing programs.

How do you know when to follow the manual approach or do something different? There is no strategy that applies all the time. What is true is that as you gain experience in computing, you will have examples of programs to use as models.

Description: testing and scaling up

It is a mark of professionalism to test your application to see if it meets the requirements of the job. In previous chapters, we have discussed the challenge of doing adequate testing when aspects of the application are random events. You must test for all situations. A related issue is that of scale. The final application may involve a large number of items. However, you often can test most of the logic using a small set.

EXAMPLE: The sample application for this chapter is the Memory game. This game can involve a large number of virtual cards. You should test your logic with a small set of cards. Test the system on the cards in a known order. Then, incorporate shuffling. Finally, once you confirm that the basic logic works, scale the project up to the number of cards that would make the game interesting. The trick here is to make the initial system incorporate all or most of the features of the final game.

TIP: A strategy for building games is to avoid the necessity of playing the game while you are building it. This may lead back to the issue of how to handle randomness. One tactic is to take randomness out of the initial implementation. Another tactic is to include randomness, but make aspects of the application visible so you, as developer/tester, know the state of the game.

Reading Checks

1. Describe the use of index values to access and set elements of an array.

2. An array in JavaScript can have elements of different datatypes. Produce the JavaScript for an array in which the first (index 0) element is a string holding a name of a month, the second (index 1) is an integer holding the day, and the third (index 2) is an integer holding the year. Make the values correspond to today's date.

3. Assume that an array holds the set of sales for a store for 12 months of a given year. The 0th element would be the sales for January, the 1st for February and so on. Write the for-loop to add up the sales to determine the yearly total.

4. Assuming two arrays holding monthly sales figures, one for one year and one for the previous year, write a for-loop to determine how many months the later year exceeded the total of the prior year.

5. Assuming the arrays of the previous two examples, using the splice method, produce the array for June, July and August sales amounts.

6. For any array, use the splice method to produce the same effects as the pop method.

7. Describe differences between the Memory application as played with cards, the real-world, manual application, and the computer implementation as shown here.

8. Describe what is meant by scaling up an application.

Application

Review of previous examples

In Chapter 4, the timed version of the Find Daniel game made use of timed events. The timed event was started when the player began the game. If the timed event happened, the specified event handler displayed a screen saying that time was up. The timed event was stopped if the player did locate Daniel correctly. Unlike the more subtle requirement that occurs in the Memory game, the timed version of Find Daniel called explicitly for a pause.

The rock-paper-scissors game in Chapter 6 make use of an array, options, to hold the strings "rock", "paper", and "scissors". The elements in this array were never changed. Similarly, the craps game featured in Chapter 7 made use of an array of images called faces for the die faces and this array was never modified.

Plan of attack for Memory

The plan is to build and debug the application using a small number of cards. What is an appropriate number? It seems that 3 pairs, for a total of 6 cards, test the application adequately: two pairs seems too small. Shuffling the cards will be done explicitly by using an tag with the call to shuffle. This provides a way to NOT shuffle for the initial testing and then check that shuffling works. This will be changed in the final version of the application.

Most of the HTML and JavaScript features necessary for this application have been covered before.

The game board is laid out using tags in the body element of the html document. The src attribute of each image is changed to switch between the card back and the card face. The document.images collection is used to access individual cards. The faces of each card are stored in an array named faces. The program uses the information in the faces array to know what image is to appear for each image. The parallel structures of tags and the faces array are what implements the virtual cards.

Each is the contents of an a element. The href attribute of the tag is assigned the value of a call to a function, choose, with the parameter for the call indicating which image.

The cards are shuffled by shuffling the faces arrays. There are many ways of shuffling. The method used here is intended to simulate how children mix up cards when playing Memory.

The pause is coded into the program by code in the choose function that invokes the setTimeout command to call a function check after a fixed amount of time. The check function does the checking and, as appropriate, restores the card back image to the images.

A variable named ctr is used to keep track of the number of matches. When all matches have been made, the game is over.

The necessity to prevent a player from cheating by clicking on more than two cards was not immediately obvious to the author. This is why you recruit other people to test your programs. A solution is to use a variable, turns, to keep count of the number of cards revealed. The choose function simply returns without doing anything if the value of turns is 2.

The outline for the html document is

html

head

script

global variables

choose function

check function

shuffle function

body

heading and instructions

table holding a elements holding img elements

hyperlink calling shuffle function

An appropriate method of document for applications in a table indicating function calls. This application has three functions:

|function |invoked by | invokes |

|choose |javascript code in tags in table. |setTimeout |

| |Contents are images | |

|check |setTimeout action | |

|shuffle |javascript code in tag with contents | |

| |Shuffle cards | |

Use of concepts in implementation

The application makes use of the faces array and 6 other global variables. The location of the image file names in the faces array determines which face will appear for each card. It is up to the programmer to make sure the array elements correspond to pairs of file names. Here is an appropriate declaration:

var faces = new Array('bird.gif', 'heart.gif', 'frog.gif', 'frog.gif', 'bird.gif', 'heart.gif');

The numOfMatches variable is used together with the variable cntr to determine if the game is over. To ease scaling up the application to hold more cards, numOfMatches is defined in terms of the number of elements in the faces array. The length property returns the number of elements for any array. The cntr variable is initialized to zero.

var numOfMatches = .5*faces.length;

var cntr = 0;

The turns variable, as indicated in the previous section, is used to prevent cheating. It must be initialized to zero.

var turns =0;

The choose function stores the index values indicating what card has been selected by the player. These values are stored in the global variables firstchoice and secondchoice. They do not need to be initialized.

var firstchoice;

var secondchoice;

The virtual flipping back of cards to show the card back and not the face means that it is necessary to 'remember' the image file name. This is done using a variable:

var backcard ="blank.gif";

The explanation of how the functions work is better done after describing what is in the body of the document.

| |starting tag |

|Memory game |heading giving name of game |

| Click on first one and then a second card. Try to make matches. Matched pairs will |instructions |

|stay visible. Click on shuffle cards for new arrangement. | |

| | |

| |starting tag for table |

| |start of row |

| |table datum holding an a element with |

| |contents an img. Note href value is a |

| |call to choose with parameter 0 |

| |.. parameter 1 |

| |End row and start new row |

| |table datum, call with parameter 2 |

| |table datum, call with parameter 3 |

| |End row and start new row |

| |table datum, call with parameter 4 |

| |table datum, call with parameter 5 |

| |End row |

| |End table |

| |Paragraph tag to provide spacing |

|Shuffle cards |This href has value call to shuffle |

| |end body |

The choose function is invoked, as indicated, with parameter holding the index value of the image. Its job is to reveal the card faces, save information for later checking, and start the timed event using setTimeout. This operation both inserts the pause and sets up the call to the check function.

|function choose(card) { |function header line |

|if (turns==2) { return ;} |Immediately return if turns is 2 |

|if (turns==0) { |If turns is 0, it is a 'first turn' |

| firstchoice=card; |Save card value |

| document.images[card].src = faces[card]; |Show face of this card using the images|

| |collection and the faces array. |

| turns = 1; |Set turns to 1 |

| } |End clause |

|else |Else (only possibility is turns = 1) |

| { turns = 2; |Set turns to 2 |

| secondchoice = card; |Save card value |

| document.images[card].src =faces[card]; |Show face of this card |

| setTimeout("check()",1000); |Start timed event to invoke check after|

| |1 second |

| } |Close else clause |

|} |Close function |

The check function

|function check() { |function header |

| if (faces[secondchoice]==faces[firstchoice]) { |Use the stored index values to access |

| |the elements in faces to check if they |

| |are the same |

| cntr++; |If they are, increment cntr to indicate|

| |one more match found |

| if (cntr == numOfMatches) { |Check if game is over |

| alert("You won. Reload/refresh to replay"); |If true, use alert to tell player |

| } |End clause |

| turns = 0; |Reset turns to zero |

| return ; |Return |

| } |End clause |

| else { |Else (no match) |

| document.images[firstchoice].src = backcard; |Virtually flip cards back: make this |

| |image show the backcard image |

| document.images[secondchoice].src = backcard; |Same for the second choice |

| turns = 0; |Reset turns to zero |

| return ; |Return |

| } |End clause |

|} |End function |

Shuffling is the subject of many research articles. The approach here is to mimic how many children mix up cards: by taking pairs and swapping them. This is done in code by randomly selecting two integers to be the index values for two elements in the faces array. Suppose these values are i and j. The elements at these positions in the array are swapped. The code is

holder = faces[i];

faces[i] = faces[j];

faces[j] = holder;

Notice that swapping requires an extra variable, in this case, the variable holder.

The number of swaps is set at twice the size of faces. A for-loop is used to do the swaps.

|function shuffle() { |function header |

|var holder; |used in the swapping |

|var swapcount = 2* faces.length; |set number of swaps |

|var swaps; |index variable for for-loop |

|var i; |used for swapping |

|var j; |used for swapping |

|for (swaps=0; swaps ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download