By Zevan | February 4, 2010
Today's quiz is not multiple choice. Instead, your task is to write a lisp style math parser. This may sound tricky, but it's surprisingly simple. (well... not simple exactly, it's just simple compared to what one might assume).
Lisp uses prefix notation... where the operator is placed before the operands:
10 * 10
becomes:
* 10 10
You could think of this as a function "*" with two arguments (10, 10). In Lisp this is enclosed with parens:
(* 10 10)
Let's see a few more examples:
100 / 2 + 10
becomes:
(+ (/ 100 2) 10)
...
2 * 4 * 6 * 7
becomes:
(* 2 4 6 7)
...
(2 + 2) * (10 - 2) * 2
becomes
(* (+ 2 2) (- 10 2) 2)
Remember, thinking "functions" really helps. The above can be though of as:
multiply( add(2, 2), subtract(10 , 2), 2)
You should create a function called parsePrefix() that takes a string and returns a number:
Here is some code to test if your parser works properly:
Actionscript:
-
trace(parsePrefix("(* 10 10)"));
-
-
trace(parsePrefix("(* 1 (+ 20 2 (* 2 7) 1) 2)"));
-
-
trace(parsePrefix("(/ 22 7)"));
-
-
trace(parsePrefix("(+ (/ 1 1) (/ 1 2) (/ 1 3) (/ 1 4))"));
-
-
/* Should trace out:
-
100
-
74
-
3.142857142857143
-
2.083333333333333
-
*/
I highly recommend giving this a try, it was one of those cases where I assumed it would be much trickier than it was.
I've posted my solution here.
By Zevan | November 29, 2009
Actionscript:
-
// print some floats as fractions
-
printFraction(0.5);
-
printFraction(0.75);
-
printFraction(0.48);
-
-
// try something a little more complex
-
var float:Number = 0.98765432;
-
trace("\na more complex example:");
-
printFraction(float);
-
var frac:Array = asFraction(float);
-
trace("double check it:");
-
trace(frac[0] + "/" + frac[1] +" = " + frac[0] / frac[1]);
-
-
/* outputs:
-
0.5 = 1/2
-
0.75 = 3/4
-
0.48 = 12/25
-
-
a more complex example:
-
0.98765432 = 12345679/12500000
-
double check it:
-
12345679/12500000 = 0.98765432
-
*/
-
-
-
function printFraction(n:Number):void{
-
var frac:Array = asFraction(n);
-
trace(n + " = " + frac[0] + "/" + frac[1]);
-
}
-
-
// takes any value less than one and returns an array
-
// with the numerator at index 0 and the denominator at index 1
-
function asFraction(num:Number):Array{
-
var decimalPlaces:int = num.toString().split(".")[1].length;
-
var denom:Number = Math.pow(10, decimalPlaces);
-
return reduceFraction(num * denom, denom);
-
}
-
-
// divide the numerator and denominator by the GCF
-
function reduceFraction(numerator:int, denominator:Number):Array{
-
// divide by the greatest common factor
-
var divisor:int = gcf(numerator, denominator);
-
if (divisor){
-
numerator /= divisor;
-
denominator /= divisor;
-
}
-
return [numerator, denominator];
-
}
-
-
// get the greatest common factor of two integers
-
function gcf(a:int, b:int):int{
-
var remainder:int;
-
var factor:Number = 0;
-
var maxIter:int = 100;
-
var i:int = 0;
-
while (1){
-
if (b> a){
-
var swap:int = a;
-
a = b;
-
b = swap;
-
}
-
remainder = a % b;
-
a = b;
-
b = remainder
-
if (remainder == 0){
-
factor = a;
-
break;
-
}else if (remainder==1){
-
break;
-
}else if (i> maxIter){
-
trace("failed to calculate gcf");
-
break;
-
}
-
i++;
-
}
-
return factor;
-
}
This snippet contains a few functions for calculating fractions based on float values. Writing this brought back some memories from grade school math.
Also posted in misc | Tagged actionscript, as3, flash |
By Zevan | November 28, 2009
Actionscript:
-
trace(gcf(75,145));
-
-
// outputs 5
-
-
function gcf(a:int, b:int):int{
-
var remainder:int;
-
var factor:Number = 0;
-
while (1){
-
if (b> a){
-
var swap:int = a;
-
a = b;
-
b = swap;
-
}
-
remainder = a % b;
-
a = b;
-
b = remainder
-
if (remainder == 0){
-
factor = a;
-
break;
-
}else if (remainder==1){
-
-
break;
-
}
-
}
-
return factor;
-
}
I was messing around with Egyptian Fractions and found myself in need of some interesting functions. The first function I realized I would be needing was for a greatest common factor (GCF or GCD).
The above snippet is a quick implementation of Euclid's algorithm. It will return 0 if no GCF is found...
I wrote a few helper functions while working with Egyptian fractions... will post them over the next few days.
Posted in Math | Tagged actionscript, as3, flash |
By Zevan | November 27, 2009
Actionscript:
-
egyptianMultiply(12, 99);
-
-
// trace(12 * 99) // test to make sure it works
-
-
/* outputs:
-
/64 768
-
/32 384
-
16 192
-
8 96
-
4 48
-
/2 24
-
/1 12
-
---
-
1188
-
*/
-
-
-
function egyptianMultiply(valueA:Number, valueB:Number):void {
-
-
var left:Array = [];
-
var right:Array = []
-
-
// swap if valueB is smaller than value A
-
if (valueB <valueA){
-
var swap:int = valueB;
-
valueB = valueA;
-
valueA = swap;
-
}
-
-
// create left and right columns
-
var currentLeft:int = 1;
-
var currentRight:int = valueA;
-
-
while (currentLeft <valueB){
-
left.push(currentLeft);
-
right.push(currentRight);
-
currentRight += currentRight;
-
currentLeft += currentLeft;
-
}
-
-
-
// add up the right column based on the left
-
currentLeft = 0;
-
var rightSum:int;
-
var leftSum:int;
-
var i:int = left.length - 1;
-
-
while (currentLeft != valueB){
-
-
leftSum = currentLeft + left[i];
-
// if the next number causes the sum
-
// to go above valueB, skip it
-
if (leftSum <= valueB){
-
currentLeft = leftSum;
-
rightSum += right[i];
-
trace("/" + left[i] + " " + right[i]);
-
} else {
-
trace(" " + left[i] + " " + right[i]);
-
}
-
i--;
-
}
-
trace("---");
-
trace(rightSum);
-
}
Someone mentioned egyptian multiplication to me yesterday... So read a little about it here and whipped up this example. For some reason I decided to do it in processing ... once it worked I ported it to ActionScript.
The above link describing the technique I used is from http://www.jimloy.com/... I haven't spent much time digging around the site, but it appears to have some pretty nice stuff on it...
If you're curious, here is the original processing version:
JAVA:
-
-
-
-
int valueA = 10;
-
int valueB = 8;
-
-
if (valueB <valueA){
-
int swap = valueB;
-
valueB = valueA;
-
valueA = swap;
-
}
-
-
int currentLeft = 1;
-
int currentRight = valueA;
-
while (currentLeft <valueB){
-
left.add(currentLeft);
-
right.add(currentRight);
-
currentRight += currentRight;
-
currentLeft += currentLeft;
-
}
-
-
currentLeft = 0;
-
-
int result = 0;
-
int i = left.size() - 1;
-
while (currentLeft != valueB){
-
-
int temp
= currentLeft
+ (Integer) left.
get(i
);
-
if (temp <= valueB){
-
-
currentLeft = temp;
-
-
println("/" + left.get(i) + " " + right.get(i));
-
} else {
-
println(" " + left.get(i) + " " + right.get(i));
-
}
-
-
i--;
-
}
-
println("---");
-
println(result);
After writing, this I took a look at the wikipedia entry... I also found myself on this short page about a scribe called Ahmes. (I recommend reading this if you are interested in PI)
By Zevan | October 20, 2009
Actionscript:
-
[SWF(width = 500, height = 500)]
-
-
var txt:TextField = TextField(addChild(new TextField()));
-
txt.defaultTextFormat = new TextFormat("_sans", 4);
-
txt.width = stage.stageWidth;
-
txt.height = stage.stageHeight+4;
-
txt.z = -1;
-
txt.x = stage.stageWidth
-
txt.rotation = 90;
-
var count:int = 0;
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void{
-
count++;
-
txt.appendText(triangular(count).toString(2) + "\n");
-
txt.scrollV= txt.maxScrollV;
-
}
-
function triangular(n:int):int{
-
return (n * (n + 1)) / 2;
-
}
Calculate some triangular numbers... (n * (n + 1)) / 2....
Check out the swf on wonderfl
Also posted in misc | Tagged actionscript, as3, flash |
By Zevan | October 19, 2009

Saw this optical illusion today... figured I'd make a snippet to create a few variations on the illusion...
Actionscript:
-
[SWF( backgroundColor=0x2E7999, width=780, height = 600) ]
-
-
var leafNum:Number = 375;
-
var spacing:Number = 12;
-
var cols:Number = 25;
-
var hh:Number = stage.stageHeight / 2;
-
var hw:Number = stage.stageWidth / 2;
-
-
for (var i:Number = 0; i<leafNum; i++){
-
var leaf:Shape = makeLeaf();
-
leaf.scaleX = leaf.scaleY = 0.25;
-
leaf.rotation = 90;
-
leaf.x = 50 + (i % cols) * (leaf.width + spacing);
-
leaf.y = 40 + int(i / cols) * (leaf.height + spacing);
-
var dx:Number = leaf.x - hw;
-
var dy:Number = leaf.y - hh;
-
leaf.rotation = Math.sqrt(dx * dx + dy * dy);
-
}
-
-
function makeLeaf():Shape{
-
var leaf:Shape = Shape(addChild(new Shape()));
-
leaf.graphics.beginFill(0x9DC4D4);
-
scaleYcircle(leaf.graphics, 50, .65, false);
-
leaf.graphics.endFill();
-
leaf.graphics.lineStyle(2, 0x003366, 1, false, "none", CapsStyle.SQUARE, JointStyle.MITER);
-
scaleYcircle(leaf.graphics, 50, .65);
-
leaf.graphics.lineStyle(2, 0xFFFFFF, 1, false, "none", CapsStyle.SQUARE, JointStyle.MITER);
-
scaleYcircle(leaf.graphics, -50, .65);
-
return leaf;
-
}
-
-
-
// original circle function by senocular (www.senocular.com) from here http://www.actionscript.org/forums/showthread.php3?s=&threadid=30328
-
// circle that can be scaled on the y axis
-
function scaleYcircle(g:Graphics, r:Number, s:Number = 1, isHalf:Boolean=true):void {
-
-
var c1:Number = r * (Math.SQRT2 - 1);
-
var c2:Number = r * Math.SQRT2 / 2;
-
var rs:Number = r * s, c1s:Number = c1 * s, c2s:Number = c2 * s;
-
var x_r:Number = -r, y_r:Number = -rs, x_c2:Number = -c2;
-
var y_c2:Number = -c2s, x_c1:Number = -c1, y_c1:Number = -c1s
-
g.moveTo(r, 0), g.curveTo(r, c1s, c2, c2s);
-
g.curveTo(c1, rs, 0, rs), g.curveTo(x_c1,rs, x_c2, c2s);
-
g.curveTo(x_r, c1s, x_r, 0);
-
if (!isHalf){
-
g.curveTo(x_r,y_c1,x_c2,y_c2);
-
g.curveTo(x_c1,y_r,0,y_r), g.curveTo(c1,y_r,c2,y_c2);
-
g.curveTo(r,y_c1,r,0);
-
}
-
}
By Zevan | October 12, 2009
Actionscript:
-
const A:uint = 1;
-
const B:uint = 2;
-
const C:uint = 4;
-
const D:uint = 8;
-
const E:uint = 16;
-
-
function orArgs(args:uint):void{
-
if (args & A){
-
trace("A");
-
}
-
if (args & B){
-
trace("B");
-
}
-
if (args & C){
-
trace("C");
-
}
-
if (args & D){
-
trace("D");
-
}
-
if (args & E){
-
trace("E");
-
}
-
}
-
-
// test out the function:
-
orArgs(A | B);
-
trace("--");
-
orArgs(A | C | E);
-
trace("--");
-
orArgs(B | E | D);
-
trace("--");
-
orArgs(C | A);
-
-
/* outputs:
-
A
-
B
-
--
-
A
-
C
-
E
-
--
-
B
-
D
-
E
-
--
-
A
-
C
-
*/
If you've every used Array.sort(Array.NUMERIC | Array.DESCENDING) you should have at least a vague idea about what this snippet is doing. It shows how you can pass a variable number of arguments to a function using | (bitwise OR) and & (bitwise AND). I believe the correct term for these kind of arguments is "bitwise flags". This snippet works by having a series of constant values... in this case A - E. Each constant is assigned an unsigned integer... now you may not see the significance of the values 1, 2, 4, 8 and 16 until you see them in binary... get ready this is a pretty cryptic description...
A = 00001 = 1
B = 00010 = 2
C = 00100 = 4
D = 01000 = 8
E = 10000 = 16
If we OR all these together we get: 11111... If we do:
A | E
00001 | 10000
we end up with 10001...
...we can then check which values are stored in the resulting unsigned integer by using AND:
check for A... 10001 & 00001 = 00001 = true
check for E... 10001 & 10000 = 10000 = true
check for C... 10001 & 00100 = 00000 = false
That's it... I just guessed at the way this was being done... if you have another way to do the same thing, feel free to post it in the comments....
By Zevan | October 11, 2009
Actionscript:
-
var inside:Number = 0
-
var precision:Number = 1000000;
-
for (var i:int = 0; i<precision; i++){
-
var xp:Number = 0.5 - Math.random();
-
var yp:Number = 0.5 - Math.random();
-
if (Math.sqrt(xp * xp + yp * yp) <0.5){
-
inside++;
-
}
-
}
-
trace(inside / precision * 4);
-
// outputs : 3.143304
Someone described this bad method of a PI approximation to me the other day... figured I'd try it out... pretty funny. I always liked 22/7... but this one is definitely funnier...
Posted in Math | Tagged actionscript, as3, flash |
By Zevan | October 5, 2009
Actionscript:
-
[SWF(width=950, height=600)]
-
with (graphics) beginFill(0xefefef), drawRect(0,0,stage.stageWidth, stage.stageHeight);
-
var btn:Sprite = Sprite(addChild(new Sprite()));
-
with (btn.graphics) beginFill(0x666666), drawRect(0,0,100,20);
-
with(btn) x=320, y=430, buttonMode = true;
-
btn.addEventListener(MouseEvent.ROLL_OVER, function():void{
-
with(btn.graphics) clear(), beginFill(0x222222), drawRect(0,0,100,20);
-
});
-
btn.addEventListener(MouseEvent.ROLL_OUT, function():void{
-
with(btn.graphics) clear(), beginFill(0x666666), drawRect(0,0,100,20);
-
});
-
btn.addEventListener(MouseEvent.CLICK, function():void{
-
var res:*= ExternalInterface.call("function(){ plot=[]; colors=[]; " + txt.text + " return {plot:plot, colors:colors};}");
-
render((res == null) ? {plot:[], colors:[]} : res);
-
});
-
-
var v:Shape = Shape(addChild(new Shape()));
-
v.x = 700;
-
v.y = 220;
-
function render(obj:Object):void{
-
var plot:Array = obj.plot;
-
var colors:Array = obj.colors;
-
var leng:int = plot.length;
-
v.graphics.clear();
-
var inc:int = 0;
-
v.graphics.moveTo(plot[0], plot[1]);
-
for (var i:int = 2; i<leng; i+=2){
-
v.graphics.lineStyle(0,colors[inc++]);
-
v.graphics.lineTo(plot[i], plot[i + 1]);
-
}
-
}
-
-
-
var submit:TextField = TextField(btn.addChild(new TextField()));
-
submit.defaultTextFormat = new TextFormat("_sans", 12);
-
with(submit) textColor=0xFFFFFF, width=100, autoSize="center";
-
with(submit) mouseEnabled = false, text="submit";
-
-
var txt:TextField = TextField(addChild(new TextField()));
-
with(txt) x = y = 20, type = "input", multiline=true;
-
with(txt) width = 400, height = 400, border = true, background = 0xFFFFFF;
-
txt.defaultTextFormat = new TextFormat("Monaco", 12);
-
txt.text = "enter text";
-
txt.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
-
function onDown(evt:MouseEvent):void{
-
txt.text = "";
-
txt.removeEventListener(MouseEvent.MOUSE_DOWN, onDown);
-
}
This snippet is a mini code editor that allows the user to write javascript into a textfield - the javascript is then run using external interface. Optionally the javascript code can populate two arrays (plot and colors). If these arrays are populated flash, will render the data in each array using the Graphics class.
Have a look at the demo:

If you do something nice with this... post your javascript snippet as a comment and I'll add it to the JS Sketch page...
By Zevan | October 3, 2009
Actionscript:
-
var txt:TextField = TextField(addChild(new TextField()));
-
txt.autoSize = TextFieldAutoSize.LEFT;
-
-
var myVar:Number = 100;
-
// works as an expression parser
-
txt.text = js("return (" + myVar + " * 2 + 10) / 2");
-
txt.appendText("\n\n");
-
-
// parses javascript
-
txt.appendText(js("var a = []; for (var i = 0; i<10; i++){ a.push(i) } return a;"));
-
-
function js( data:String ):*{
-
var res:*= ExternalInterface.call("function(){" + data + "}");
-
return (res == null) ? "null" : res;
-
}
This one made my day - CAN'T believe I never thought of it before... haven't done any speed tests yet... but it shows how to use ExternalInterface.call to parse math expressions and javascript code. This will only work when the swf is shown in an html page of course... so if your in flash cmd+f12...
I got the idea from this code snippet... which actually has an error in it... the decode() function should not return void... I found that snippet thanks to this tweet by makc3d.