A question came up today about sorting matrices of data in ActionScript. The resolution was rather simple but I’ve heard through the grapevine that [students] might have some utility for this, so here it is. And since we’re at it, let’s also add in the idea that the data is being fed from an external XML document.
Here’s the scenario that we faced. iStreamPlanet produces a software application that is run during live poker tournaments which places an overlay on top of the encoded video similar to poker tournaments you might see on TV. The actual system uses an interface built in C++ that writes an XML file as it is updated, which in turn is read by a Flash component layer and then drawn into the video card (the result is something that looks like the image below).

For those of you who have been through any of the scripting classes, by now you should recognize that this needs a multi-dimensional array to work best. Don’t be scared off by multi-dimensional arrays – think of them as just Excel spreadsheets. So if you have a spreadsheet that looks something like this:
| A | B | C | D | |
| 1 | Hat | Cat | Rat | Sat |
| 2 | Bar | Car | War | Par |
Then the your array would have been written as:
| var myArray = new Array(); myArray[0][0] = "Hat"; myArray[0][1] = "Cat"; myArray[0][2] = "Rat"; myArray[0][3] = "Sat"; myArray[1][0] = "Bar"; myArray[1][1] = "Car"; myArray[1][2] = "War"; myArray[1][3] = "Par"; |
Download the materials here: Multi-Dimensional Array Sorting from XML Data in ActionScript (ZIP)
In the course of adding components to the application, we needed to output the current chip counts of each player and present them in order of most to least chips. Of course, our XML ordering was based on the C# output which was not sorted and also contained string data where we needed to sort numerically.
| <?xml version="1.0" encoding="ISO-8859-1"?> <PlayersData> <Title>President Poker</Title> <GameOver>FALSE</GameOver> <DisplayMode>0</DisplayMode> <PlayersChipCount> <Player ID="1" Name="George Bush">$454</Player> <Player ID="2" Name="George Washington">$545,445</Player> <Player ID="3" Name="Ronald Reagan">$454,545</Player> <Player ID="4" Name="Bill Clinton">$54,545</Player> <Player ID="5" Name="John F. Kennedy">$787</Player> <Player ID="6" Name="Richard Nixon">$4,554</Player> <Player ID="7" Name="Theodore Roosevelt">$15,616</Player> <Player ID="8" Name="Abraham Lincoln">$564,564</Player> <Player ID="9" Name="James Madison">$5,451</Player> </PlayersChipCount> <!-- data removed here --> <PlayersData> |
First, we read the XML. To do this you’ll need to open a socket:
| xmlData = new XML(); xmlData.ignoreWhite = true; xmlData.load("Data.xml"); |
Next, we created a function that broke up the data and put it into the array.
| xmlData.onLoad = readCart; function readCart(success){ if (!success){ trace("Error: CANNOT LOAD XML DATA"); break; }else{ trace("XML read successfully"); for (i = 0; i < this.childNodes.length; i++){ if (this.childNodes[i].nodeValue == null && this.childNodes[i].nodeName == "PlayersData"){ topLevel = this.childNodes[i]; } } }//function continues below |
At this point we need to consider how to sort the data. Remember that our original spec required that the output be sorted in descending chip count order. But notice that the XML data that has symbols in it. If you know a bit about programming, you’ll know that sorting is done based on the operating system preference. In this case using a normal sort() function, Player 7 (Roosevelt) with $15,616 chips would be first…
| Unparsed Sort | Correct Sort | ||
| Roosevelt | $15,616 | Lincoln | $564,564 |
| Bush | $454 | Washington | $545,445 |
| Reagan | $454,545 | Reagan | $454,545 |
| Nixon | $4,554 | Clinton | $54,545 |
| Madison | $5,451 | Roosevelt | $15,616 |
| Washington | $545,445 | Madison | $5,451 |
| Clinton | $54,545 | Nixon | $4,554 |
| Lincoln | $564,564 | Kennedy | $787 |
| Kennedy | $787 | Bush | $454 |
While ActionScript does have conversion capabilities, the problem in this scenario is that the symbols will not allow conversion to a numeric. So let’s create a function that will “convert” the formatted field into a number.
| function replace(origStr,searchStr) { var tempStr = ""; var startIndex = 0; for (c = 0;c < origStr.length;c++) { thischar = origStr.substr(c,1); if ( thischar != searchStr ) { tempStr += thischar; } } return tempStr; } |
Using the conversion function (and note, you can use this function – albeit very simplistic – to do pretty much any type of string replacement), now we can finish off the original function.
| //create empty array container var dat:Array = Array(); //loop through array data for (i = 0; i <= 4; i++){ //create empty array for internal data var dat2:Array = Array(); //extract node data var playID = topLevel.childNodes[3].childNodes[i].attributes.ID; var playName = topLevel.childNodes[3].childNodes[i].attributes.Name; var playChip = topLevel.childNodes[3].childNodes[i].childNodes[0]; //set data into internal array //not sequence of functions (inside out): // 1. set playChip to a string - node data is being held as an object // 2. replace $ with a blank (see function) // 3. replace , with a blank (see function) // 4. set value as a numeric dat2[0] = Number(replace(replace(playChip.toString(),"$"),",")); dat2[1] = playID; dat2[2] = playName; dat2[3] = playChip; //set internal array into external array //this creates a multi-dimensional array dat[i] = dat2; } //sort on index 0 with Numeric descending dat.sortOn([0],2|16);//trace output for (i = 0; i <= 4; i++) { trace(i+". "+dat[i][3]+" "+dat[i][2]+" at "+dat[i][4]+" each"); } } |
Now test the movie (Ctrl+Enter) and check out the chip counts.
Incidentally, if you’re a poker buff, check out how this actually looks on screen by watching the World Series of Poker at http://www.worldseriesofpoker.com/