Applet and Code

This tutorial addresses the following question from a flashandmath.com reader:

Thank you for your well written (and well commented) tutorial on creating XML based quizzes in Flash. We are finding it very informative here in our classroom. One question is puzzling me: How would I change the actionscript code to enable the quiz to present a random set of questions from a longer list? For example, could I have the quiz present just 4 random questions from an XML file containing 20 questions in total?

This is a general issue, whether you are trying to scramble images, randomly choose quiz problems, or simulating the dealing of a hand of playing cards. In the present tutorial, we show how to accomplish a random selection of a subset of a given array of objects. To minimize the "overhead" in our example, we will set up an array of strings, each representing a playing card in a standard deck of 52 cards. The applet allows the user to specify the number of cards that should be randomly selected, which we think of as a "hand" in a card game. The code uses a function (which we call getHand because of the context) that can easily be copied for use in any situation where a random subset of a set of objects needs to be chosen. Click the screen shot below or this link to open the applet in a new window:

Download

Download the well-commented source file corresponding to the applet above, dealhand.fla.

The Code

For this example, we use an array of strings, each representing a card from a deck of playing cards.

var cards:Array = ["AC","2C","3C","4C","5C","6C","7C","8C","9C","TC","JC","QC","KC",
"AH","2H","3H","4H","5H","6H","7H","8H","9H","TH","JH","QH","KH",
"AS","2S","3S","4S","5S","6S","7S","8S","9S","TS","JS","QS","KS",
"AD","2D","3D","4D","5D","6D","7D","8D","9D","TD","JD","QD","KD"];

When a keyboard key is pressed down, we call the function dealHand below. This function simply gets the number entered by the user in the txtNumber input box, calls the main function that follows to get the appropriate number of random elements from the cards array, and puts the output into the dynamic textbox txtOutput.

stage.addEventListener(KeyboardEvent.KEY_DOWN, dealHand);

 

function dealHand(ke:KeyboardEvent):void {

var i:int;

var hand:Array;

 

// If the key that is down is _not_ the ENTER key, we return from this function having done nothing.

if (ke.keyCode != Keyboard.ENTER) {

return;

}

 

// Let handSize be the number in the txtNumber box; if this cannot be interpreted as a number between 1 and 52, then we just let handSize equal 1 or 52.

var handSize:int = int(txtNumber.text);

if (handSize < 1) handSize = 1;

if (handSize > 52) handSize = 52;

 

// It's good practice to put back in txtNumber the actual number you will be using for handSize.

txtNumber.text = String(handSize);

// Call the function that returns an array containing random elements from the cards array.

hand = getHand(cards,handSize);

 

// Output the array that has the randomly chosen elements from the original array.

txtOutput.text = "Here is your " + String(handSize) + "-card hand:\n\n";

 

for (i=0; i<handSize; i++) {

 

// List one card at a time followed by a space.

txtOutput.appendText(hand[i]+" ");

}

}

The function getHand takes as input an array of objects (arr) and a number of those objects (k) you would like to randomly choose. The output is an array containin k randomly chosen elements of arr. It works using Math.random to facilitate choosing a random object and the splice method of the Array class to remove an object from one array so it can be put into the other. We explain the Array.concat and Array.splice methods in the next section.

function getHand(arr:Array,k:int):Array {

var i:int;

var rand:int;

 

// Make a temporary array that initially matches the arr array.

var temp:Array = arr.concat();

 

// The hand array starts off empty but will eventually contain k cards.

var hand:Array = new Array();

 

for (i=0; i<k; i++) {

// If temp contains no elements, we are not going to be able to choose any more cards, so we get out of the loop.

if (temp.length == 0) break;

 

// Get a random number from 0, 1, 2, ..., (length of temp array)-1. These are simply all the legit indices for the temp array.

rand = Math.floor(temp.length * Math.random());

 

// Put the element at temp[rand] into the hand array and remove it from the temp array.

hand.push(temp.splice(rand,1)[0]);

}

return hand;

}

Below we explain two basic methods of the Array class that we used in our code.

The Array.concat Method and Cloning an Array

The method:

Array.concat(...args):Array

Concatenates the elements specified in the parameters with the elements in an array and creates a new array. If the parameters specify an array, the elements of that array are concatenated. For example:

var arr1:Array = [1,2,3];

var arr2:Array = ["green","blue"];

var arrResult:Array = arr1.concat(arr2);

trace(arrResult);

trace(arr1);

The outpput window shows:

1,2,3,green,blue
1,2,3

The array arr1 has not been altered. A new concatanated array arrResult=[1,2,3, "green","blue"] was created.

In particular, if you don't pass any parameters to the 'concat' method, you are creating a copy of your array:

var arrResult2:Array = arr1.concat();

trace(arrResult2);

gives the array 1,2,3. The copy of your array obtained via the 'concat' method is a shallow clone. That is, if elements of your array are objects other than primitive datatypes like numbers or strings, the objects are passed to the clone by reference only. So if the objects change, they will change in both the original array and in its clone.

The Array.splice Method

The method

Array.splice(startIndex:int, deleteCount:uint, ... values):Array

removes elements from an array, returns the array of removed elements, and possibly ads elements to the array if some values are specified. This method does alter the array to which it is applied (unlike 'concat' which creates a new array). More precisely, splice will remove deleteCounter number of elements beginning with startIndex to startIndex+deleteCount-1. If any number of 'values' are specified, the method will insert 'values' beginning with startIndex position. For example:

var arr:Array = [10,20,30,40,50,60];

var arrReturn:Array;

arrReturn = arr.splice(1,3,"e1","e2","e3","e4");

trace(arr);

trace(arrReturn);

gives

10,e1,e2,e3,e4,50,60
20,30,40
.

So after splicing 'arr' becomes: arr = [10,"e1","e2","e3","e4",50,60]. The splice method returns the array of deleted elements [20,30,40].

In our code we applied the method within getHand function to an array temp. Initially temp was a copy of the array of cards cards. At each step, we removed one element from temp at a randomly generated place rand. That is accomplished by:

temp.splice(rand,1)

We are removing only one element as the second parameter (deleteCount) is 1. The splice method returns the array of removed elements, in our case a one-element array. We retrive the removed element by temp.splice(rand,1)[0];, and add it to the array hand via the push method:

hand.push(temp.splice(rand,1)[0]);

Back to AS3 How-Tos and Tips              Back to Flash and Math Home

We welcome your comments, suggestions, and contributions. Click the Contact Us link below and email one of us.

Adobe®, Flash®, ActionScript®, Flex® are registered trademarks of Adobe Systems Incorporated.