//------------------------------------------------------------------------------ // TScriptArray Resource // Provided for free use by James C Ford // // Versions // // 1.2 July 26, 2008 Added reverse, getRandom, and sort // // 1.1 July 17, 2008 Added push_front, pop_front, and insert // // 1.0 July 15, 2008 // //------------------------------------------------------------------------------ // // Create and return a new TScriptArray object. // function TScriptArray::create() { %obj = new ScriptObject() { class = "TScriptArray"; elementCount = 0; }; return %obj; } // // Add a new element to the end of the array with the given value. // function TScriptArray::push_back( %this, %val ) { %this.array[%this.elementCount] = %val; %this.elementCount++; } // // Remove the last element of the array and return its value. // function TScriptArray::pop_back( %this ) { if ( %this.elementCount < 1 ) { echo( "TScriptArray::pop_back, invalid with zero elements" ); return; } %val = %this.array[%this.elementCount - 1]; %this.array[%this.elementCount - 1] = ""; %this.elementCount--; return %val; } // // Add a new element to the front of the array with the given value, // pushing all other elements back one in the array. // Note that this is more expensive than push_back. // function TScriptArray::push_front( %this, %val ) { for ( %i = %this.elementCount; %i > 0; %i-- ) { %this.array[%i] = %this.array[%i-1]; } %this.elementCount++; %this.array[0] = %val; } // // Remove the first element of the array and return its value. // Preserves the order of all other elements in the array. // Note that this is more expensive that pop_back. // function TScriptArray::pop_front( %this ) { if ( %this.elementCount < 1 ) { echo( "TScriptArray::pop_front, invalid with zero elements" ); return; } %val = %this.array[0]; for ( %i = 0; %i < %this.elementCount; %i++ ) { %this.array[%i] = %this.array[%i+1]; } // Not technically necessary to clear this, // but protects against someone manipulating elementCount %this.array[%this.elementCount-1] = ""; %this.elementCount--; return %val; } // // Insert a new element with the given value at the specified // element index. The existing element at that index and all those // after it will be pushed to the "right" one element in the array. // function TScriptArray::insert( %this, %idx, %val ) { if ( %idx >= %this.elementCount ) { echo( "TScriptArray::insert, " @ %idx @ " is outside of the array bounds" ); return; } for ( %i = %this.elementCount; %i > %idx; %i-- ) { %this.array[%i] = %this.array[%i-1]; } %this.elementCount++; %this.array[%idx] = %val; } // // Set the value of an existing element in the array. // function TScriptArray::set( %this, %idx, %val ) { if ( %idx > %this.elementCount - 1 ) { echo( "TScriptArray::setElement, " @ %idx @ " is outside of the array bounds" ); return; } %this.array[%idx] = %val; } // // Return the value of an existing element in the array. // function TScriptArray::get( %this, %idx ) { if ( %idx < 0 || %idx > %this.elementCount - 1 ) { echo( "TScriptArray::getElement, " @ %idx @ " is outside of the array bounds" ); return; } return %this.array[%idx]; } // // Returns the number of elements in the array. // function TScriptArray::size( %this ) { return %this.elementCount; } // // Search for a value in the array and return the element // index of the first occurance. // function TScriptArray::find( %this, %val ) { for ( %i = 0; %i < %this.elementCount; %i++ ) { if ( %this.array[%i] $= %val ) return %i; } return -1; } // // Remove an element from the array and preserve order. // function TScriptArray::erase( %this, %idx ) { if ( %idx > %this.elementCount - 1 ) { echo( "TScriptArray::erase, " @ %idx @ " is outside of the array bounds" ); return; } %this.array[%idx] = ""; for ( %i = %idx; %i < %this.elementCount - 1; %i++ ) { %this.array[%i] = %this.array[%i+1]; } %this.elementCount--; } // // Remove an element from the array faster, but does not // preserve order. Copies the last element into the hole. // function TScriptArray::erase_fast( %this, %idx ) { if ( %idx > %this.elementCount - 1 ) { echo( "TScriptArray::erase_fast, " @ %idx @ " is outside of the array bounds" ); return; } %this.array[%idx] = ""; %this.array[%idx] = %this.array[%this.elementCount - 1]; %this.array[%this.elementCount - 1] = ""; %this.elementCount--; } // // Print all array elements to the console. // function TScriptArray::print( %this ) { echo( "---Printing ScriptArray---" ); if ( %this.elementCount == 0 ) echo( " [EMPTY]" ); for ( %i = 0; %i < %this.elementCount; %i++ ) { echo( " element " @ %i @ ", " @ %this.array[%i] ); } } // // Clears all array elements, setting the size to zero. // function TScriptArray::clear( %this ) { // Clearing the strings is not really necessary, // But is someone screws with the elementCount, // it could be a good idea. for ( %i = 0; %i < %this.elementCount; %i++ ) { %this.array[%i] = ""; } %this.elementCount = 0; } // // Reverses the order of all elements in the array // function TScriptArray::reverse( %this ) { %i = 0; %j = %this.elementCount - 1; while ( %i <= %j ) { %temp = %this.array[%i]; %this.array[%i] = %this.array[%j]; %this.array[%j] = %temp; %i++; %j--; } } // // Returns the value of a random element in the array. // function TScriptArray::getRandom( %this ) { if ( %this.elementCount == 0 ) { error( "TScriptArray::getRandom, not valid with zero elements!" ); return; } %idx = getRandom( 0, %this.elementCount - 1 ); return %this.array[%idx]; } // // Sort the array using the passed comparison function. // // Example(s): // $array.sort( "compareStrings", true ); // $array.sort( "compareDigits", true ); // // %compare must be the name of a function you implement // which takes two parameters and returns -1 if the first // is less than the second, 1 if the first is greater than // the second, and 0 if they are equal. Look below for // examples that work for sorting strings and digits. // // Notes: this is is a bubble sort algorithm and is NOT // suitable for a very large number of elements. Also if your // comparison function does not return the proper values // it CAN get stuck in an infinite loop. // function TScriptArray::sort( %this, %compare, %ascending ) { if ( !isFunction( %compare ) ) { error( "TScriptArray::sort, %compare is not a valid function!" ); return; } for ( %loop = true; %loop; ) { %loop = false; for ( %i = 0; %i < %this.elementCount - 1; %i++ ) { %result = call( %compare, %this.array[%i], %this.array[%i+1] ); // The elements are equal if ( %result == 0 ) continue; // Swap the sign if necessary if ( %ascending ) { %result = (%result > 0) ? -1 : 1; } // Swap the elements if ( %result < 0 ) { %temp = %this.array[%i]; %this.array[%i] = %this.array[%i+1]; %this.array[%i+1] = %temp; // We didn't make it through the list without a swap, // so keep looping %loop = true; } } } } function compareStrings( %a, %b ) { return strcmp( %a, %b ); } function compareDigits( %a, %b ) { return ( %a - %b ); }