Browse the notebook

Category: strings

Hill Climbing

var target:Array = ("actionsnippet").split("");
var leng:int=target.length;
var iterations:int = 0;

var alphabet:Array = ("abcdefghijklmnopqrstuvwxyz").split("");
var search:Array = randomString();
var indices:Array = new Array();
for (var i:int = 0; i<leng; i++) indices.push(i);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	for (var i:int = 0; i<10; i++){
		if (indices.length > 0){
		   var ii:int = int(Math.random()*indices.length);
		   var index:int = indices[ii];
		 
		   search[index] = randomChar();
		   
		   if (search[index] == target[index]){
			   indices.splice(ii,1);   
		   }
		   trace(search);
		   iterations++;
		}else{
			trace("found after "+iterations+" iterations");
			removeEventListener(Event.ENTER_FRAME, onLoop);
			break;
		}
	}
}
function randomChar():String { return alphabet[int(Math.random()*alphabet.length)]; };
function randomString():Array {
	var str:Array = new Array();
	for (var i:int = 0; i<leng; i++) {
		str.push(randomChar());
	}
	return str;
}

A little random hill climbing…

Here are the last few iterations… lowest number of iterations I noticed was round 250…

....
j,c,t,i,o,n,s,n,i,p,p,e,t
y,c,t,i,o,n,s,n,i,p,p,e,t
s,c,t,i,o,n,s,n,i,p,p,e,t
w,c,t,i,o,n,s,n,i,p,p,e,t
e,c,t,i,o,n,s,n,i,p,p,e,t
j,c,t,i,o,n,s,n,i,p,p,e,t
z,c,t,i,o,n,s,n,i,p,p,e,t
l,c,t,i,o,n,s,n,i,p,p,e,t
f,c,t,i,o,n,s,n,i,p,p,e,t
a,c,t,i,o,n,s,n,i,p,p,e,t
found after 361 iterations

Read snippet: Hill Climbing

Command Draw Source

[SWF(width = 600, height = 500, frameRate=30, background = 0xFFFFFF)]

var cmd:String = "1000 small orange circles, 9000 black lines,3 large white circles"
// try some of these commands:
//"300 small red triangles and 2 big orange circle 3 big black lines";
//"100 big black triangles, ten small white rectangles 1 big white circle and 1 big gray poly";
// "300 small red triangles and 2 big orange circle 3 big black lines";
//"10 big black circles 1000 big white lines 100 small white rects 1 big red circle and 1 green poly"
stage.align = "TL"
var msk:Shape = new Shape();
with(msk.graphics) beginFill(0x00FF00), drawRect(0,0,600, 400);
this.mask = msk;
var amount:Number;
var color:uint = 0;
var shape:String;

var hexLookup:Object = {red:0xFF0000, green:0x00FF00, blue:0x0000FF, yellow:0xFFFF00, orange:0xFFCC00, white:0xFFFFFF, gray:0xCCCCCC, grey:0xCCCCCC, black:0x000001};
var sizeLookup:Object = {large:true, big:true, small:true, tiny:true};
var defaultSize:Number = 50;
var size:Number = defaultSize;
var halfSize:Number = size / 2;
var circles:Function = circle;
var ovals:Function = oval, ellipse:Function = oval;
var rects:Function = rect, rectangle:Function = rect, rectangles:Function = rect;
var lines:Function = line;
var triangles:Function = triangle;
var polygon:Function = poly, polygons:Function = poly;
var large:Function = big;
var tiny:Function = small;

parse();
function parse():void {
	amount = 1;
	color = 0x000000;
	shape = "circle";
	var words:Array = cmd.split(/[W]+/g)
	for (var i:int = 0; i<words.length; i++){
		var w:* = words[i];
		if (isNaN(Number(w))){
			if (hexLookup[w]){
				color = hexLookup[w];
				trace(w, "color");
			}else
			if (sizeLookup[w]){
				this[w]();
			}else
			if (this[w]){
				for (var j:int = 0; j<amount; j++){
				   this[w]();
				}
				color = 0x000000;
				size = defaultSize;
				trace(w, "command");
			}
		}else{
			trace(w, "number");
			amount = w;
		}
	}
}
function makeShape(p:Array):void{
		var s:Shape = Shape(addChild(new Shape()));
		 for (var i:int = 0; i<p.length; i++) {
		    s.graphics[p[i][0]].apply(graphics,p[i].splice(1));
	     }
		s.rotation = Math.random() * 360;
		s.x = Math.random() * stage.stageWidth;
		s.y = Math.random() * stage.stageHeight;
}

function circle():void{
	  makeShape([["beginFill",color], ["drawCircle",0,0,Math.random() * halfSize + halfSize]]);
}
function oval():void{
	  makeShape([["beginFill",color],["drawEllipse", 0,0,Math.random() * size + halfSize]]);  
}
function square():void{
		var s:Number = Math.random() * halfSize + halfSize;
		var p:Number = -s/2;
		makeShape([["beginFill",color],["drawRect", p, p, s, s]]);  
}
function rect():void{
		var w:Number = Math.random() * halfSize + halfSize;
		var h:Number = Math.random() * halfSize + halfSize;
		makeShape([["beginFill",color],["drawRect", -w/2, -h/2, w, h]]);
}
function line():void{
	var s:Number = size * 2;
	makeShape([["lineStyle",Math.random()*3, color],["lineTo", Math.random()*s - size, Math.random()*s - size]])
}
function triangle():void {
	 var s:Number = size * 2;
	 makeShape([["beginFill",color],["lineTo", Math.random()*s - size, Math.random()*s - size], ["lineTo", Math.random()*s - size, Math.random()*s - size]]);
}
function poly():void {
	 var s:Number = size * 2;
	 var cmds:Array = [["beginFill",color]]
	 var num:Number = int(Math.random()*8) + 2;
	 for (var i:int = 0; i<num; i++){
		  cmds.push(["lineTo", Math.random()*s - size, Math.random()*s - size]);
	 }
	 makeShape(cmds);
}
function big():void{
	size = 100 + Math.random() * 40;
	halfSize = size / 2;
}
function small():void {
	size = 3 + Math.random() * 20;
	halfSize = size / 2;
}

I’ve been meaning to post this source for a long time. It’s a project I created for shapevent called Command Draw. It allows you to use simple sentence structure to create textures and patterns.

See it in action here (this one has some minimal UI and uses flashvars for the command string).


As a side note, this is the 200th post on ActionSnippet.com

Read snippet: Command Draw Source

2D Array to String

function format2D(a:Array):String {
	var str:String="[";
	for (var i:int = 0; i<a.length; i++) {
		str+="["+a[i].toString()+"],";
	}
	str=str.substr(0,str.length-1);
	str+="]";
	return str;
}

// test it out
var array2D:Array = [[1,2,3], [4,5,6], [7,8,9]];

trace(array2D);
trace(format2D(array2D));

/* outputs:
1,2,3,4,5,6,7,8,9
[[1,2,3],[4,5,6],[7,8,9]]

*/

When you trace a 2D array to the output window the actual structure of the array isn’t clear. For some reason it just appears as a 1D array – this small function fixes that problem – it could also be used to save 2D arrays to text files etc…

Read snippet: 2D Array to String

Object Parsing (object from string #2)

var str:String = '{numA:100, numB:100, stringA:"hi there", object:{red:155, green:155, blue: 255}, array1D:[1, 2, 3, 4, 5, "six"], array2D:[[1,0,0], [0,1,0], [0,0,"z"]], color:0xFF0000}'

var obj:Object = toObject(str);//, true); // comment the "true" in for some debug info

// acess every value in the object for testing purposes
trace(obj.numA);
trace(obj.numB);
trace(obj.stringA);
trace(obj.object.red, obj.object.green, obj.object.blue);
trace(obj.array1D +" testing access: " + obj.array1D[3]);
trace(obj.array2D + " testing access: " + obj.array2D[1] + "  -  " + obj.array2D[2][2]);
trace(obj.color);

/*outputs:
100
100
hi there
155 155 255
1,2,3,4,5,six testing access: 4
1,0,0,0,1,0,0,0,z testing access: 0,1,0  -  z
16711680
*/
 
function toObject(str:String, debug:Boolean=false):Object{
	var cmds:Array = new Array();
	var stack:String = "";
	// skip first {
	str = str.replace(/^s+{|^{/, "");
	var obj:Object = new Object();
	for (var i:int = 0; i<str.length; i++){
		var char:String = str.charAt(i);
		if (char == ":"){
			cmds.push(["name:", stack])
			stack = "";
			char = "";
		}else
		if (char == "," || char == "}"){
			if (stack != ""){
			  cmds.push(["value:", stack]);
			}
			stack = "";
			char = "";
		}else
		if (char == '"'){
			stack = '"';
			for (j = i + 1; j <str.length; j++){
				char = str.charAt(j);
				stack+=char;
				i++;
				if (char == '"'){
					 break;
				}
			}
			cmds.push(["value:", stack]);
			stack = "";
			char = "";
		}else
		if (char == "{"){
			cmds.push(["object:", stack]);
			for (var j:int = i; j <str.length; j++){
				char = str.charAt(j);
				stack+=char;
				i++;
				if (char == "}"){
					 break;
				}
			}
			cmds.push(["value:", stack]);
			stack = "";
			char = "";
		}else
		if (char == "["){
			cmds.push(["array:", stack]);
			stack = "";
			char = "";
		}else if (char == "]"){
			if (stack != ""){
				cmds.push(["value:", stack]);
			}
			stack = "";
			char = "";
			i++;
		}
		stack += char;
	}
	// show some debug info
	if (debug){
		for (i = 0; i<cmds.length; i++) trace(cmds[i]);
	}
	// build the object
	var prop:String;
	var arrayMode:Boolean = false;
	var nest:int = 0;
	for (i = 0; i<cmds.length; i++){
		if (cmds[i][0] == "name:"){
			prop = cmds[i][1].replace(/s/g, "");
			arrayMode = false;
			nest = 0;
		}else if (cmds[i][0] == "value:"){
			if (arrayMode == false){
			  obj[prop] = valueType(cmds[i][1]);
			}else{
				// populate array
				if (nest == 1){
				  obj[prop].push(valueType(cmds[i][1]))
				}else{
				  obj[prop][nest - 2].push(valueType(cmds[i][1]))
				}
			}
		}else if (cmds[i][0] == "object:"){
			i++;
			obj[prop] = toObject(cmds[i][1], debug);
		}else if (cmds[i][0] == "array:"){
			arrayMode = true;
			nest++;
			if (nest == 1){
				// create array
				obj[prop] = new Array()
			}else{
				// nested array
				obj[prop].push(new Array());
			}
		}
	}
	return obj;
}
 
function valueType(val:*):* {
	if (isNaN(Number(val))) {
		   // remove leading and trailing white
		   // remove "" around strings
		   val = val.replace(/^s+|s+$/g,"").replace(/^"|"$/g,"");
		   //  see if it's a boolean
		   if (val == "true"){
			   val = true;
		   }else if (val == "false"){
			   val = false
		   }
	} else {
		val = Number(val);
	}
	return val;
}

This rather large code snippet parses ActionScript style Object syntax. While this is by no means a complete parser – it was easy to write and saved me a great deal of time on a project recently….

I specifically needed support for 1D and 2D arrays as Object properties. If that weren’t the case I would have used something simple like yesterdays method. The array support won’t work with anything higher than a 2D array (for now… may fix that soon). For fun I also added nested Object support – this doesn’t have any dimensional limitation so you can nest as many objects as you want. For instance.. this works just fine:

var gameUser:Object = toObject('{name:"Mr.S", alive:true, stats:{lives:100, points:1200, data:[100,12,40,12,90], plant:{branch:{leaves:["red, "green", "blue"]}}}');

trace(gameUser.stats.plant.branch.leaves[0]);
trace(gameUser.stats.lives);
// boolean support
trace("not true is false: ", !gameUser.alive);
/*outputs:
red
100
not true is false:  false
*/

You’ll also notice the added boolean support in the above example. Which was suggested by katopz in the comments of yesterdays post.

Definitely need to add a word of warning here… I wouldn’t be surprised if there were a bug or two lurking in this code. The Objects I’ve been parsing with it are all quite similar… so use at your own risk.

UPDATEs – Known Issues:
1) fixed a bug where if a String property contains a ,{}[] or : character the parser failed.

Read snippet: Object Parsing (object from string #2)

Object from String

var str:String='{x: 10, y:10, width:100, heigth:100, name:"myClip", type:"clip"}';

var obj:Object=toObject(str);

trace(obj.x + obj.width, obj.name, obj.type);

function toObject(str:String):Object {
	str=str.replace(/{|}/g,"");
	// to an array of name value pairs [0] = name, [1] = value etc...
	var pairs:Array=str.split(/:|,s+/);
	var obj:Object = new Object();
	for (var i:int = 0; i<pairs.length; i+=2) {
		obj[pairs[i]]=numOrString(pairs[i+1]);
	}
	return obj;
}
function numOrString(val:*):* {
	if (isNaN(Number(val))) {
		if (val.charAt(0) == '"' && val.charAt(val.length - 1) == '"'){
			val = val.substr(1, val.length - 2);
		}
	} else {
		val=Number(val);
	}
	return val;
}

A very limited way to parse an object from a string… Tomorrow I’ll post a better version of this that’s a good deal more complex and doesn’t really use regular expressions… This works nicely if you don’t have arrays as Object properties…

Read snippet: Object from String

String.fromCharCode()

[SWF(height = 950, width=1000)]
var txt:TextField;
var num:int = 0;
for (var i:int = 0; i<761; i++){
	if (i % 76 == 0){
		 makeTxt(num);
		 num++;
	}
	if (i < 0x21){
		txt.appendText("-n");
	}else{
	    txt.appendText(String.fromCharCode(i) + " = " +  i + "n");
	}
}
function makeTxt(num:Number):void{
	 txt= TextField(addChild(new TextField()));
     txt.x = 10 + num * 100;
     txt.y = 10;
     txt.height = 930;
     txt.text = "";
}

This will draw a few columns of char codes.

Read snippet: String.fromCharCode()

String.indexOf()

var words:String = "one two three four five";

trace("two: ", words.indexOf("two"));

var letters:String = "abcd";

trace("d: ",letters.indexOf("d"));

trace("z: ",letters.indexOf("z"));

/*
outputs:
two:  4
d:  3
z:  -1
*/

indexOf() searches a string for another string and returns an index… in line 3 above, I search the words string for the smaller string “two” and indexOf() gives me the index of the letter “t”. If indexOf() doesn’t find anything it will return -1 (as in the case of line 9).

I seem to recall using this in some unexpected places. I’ll see if I can dig up an example over the next few days.

Read snippet: String.indexOf()

Zig Zag Binary ix2 & i/2

var txt:TextField = TextField(addChild(new TextField()));
txt.text = "";
txt.width = 190;
txt.height = 400;
txt.multiline = true;

var count:int = 1;
function render():void{
	var line = int(count).toString(2);
	while(line.length < 31){
		line = "0" + line;
	}
    txt.appendText(line + "n");
	txt.scrollV= txt.maxScrollV;
}

addEventListener(Event.ENTER_FRAME, onCountUp);
function onCountUp(evt:Event):void {
	count *= 2;
	render();
	if (count ==0x40000000){
		removeEventListener(Event.ENTER_FRAME, onCountUp);
		addEventListener(Event.ENTER_FRAME, onCountDown);
	}
}
function onCountDown(evt:Event):void {
	count /= 2;
	render();
	if (count ==1){
		addEventListener(Event.ENTER_FRAME, onCountUp);
		removeEventListener(Event.ENTER_FRAME, onCountDown);
	}
}

The above animates a zig zag pattern in a TextField.

Read snippet: Zig Zag Binary ix2 & i/2

MYSQL SOUNDEX

SELECT * FROM _users WHERE SOUNDEX(name) LIKE SOUNDEX('jon');

Not ActionScript, but the coolest thing I’ve seen in Mysql in awhile, the soundex function will convert a string into a soundex index… read more about it on wikipedia.

I did some tests and it matches things like:

what’s your name? & whats yer name

very cool… since this isn’t ActionScript, I will post another snippet right after this.

UPDATE: Actually started reading more about this stuff and dug up some algorithms… metaphone etc… fun stuff, maybe I’ll port some of it to actionscript…

Read snippet: MYSQL SOUNDEX