Project Euler 144
My solution to Project Euler 144,
regarding reflections of a laser
in an ellipse.
This simulates 2 bounces every frame,
my C# port of this (if used without
creating graphics) runs almost instantly.
Port stats:
Without compiler optimization:
6510ms elapsed for 100,000 runs = 0.065 ms/run
With compiler optimization:
4870ms elapsed for 100,000 runs = 0.049 ms/run
About 33 lines of C# code
♥0 |
Line 96 |
Modified 2011-10-07 06:25:18 |
MIT License
archived:2017-03-20 09:58:47
ActionScript3 source code
/**
* Copyright antalg ( http://wonderfl.net/user/antalg )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/azEG
*/
package {
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.events.Event;
import flash.text.TextField;
import flash.geom.Point;
import flash.display.Sprite;
[SWF(backgroundColor=0xDDDDDD, frameRate=30)]
//////////
///////// My solution to Project Euler 144,
//////// regarding reflections of a laser
/////// in an ellipse.
//////
///// This simulates 2 bounces every frame,
//// my C# port of this (if used without
/// creating graphics) runs almost instantly.
//
/// Port stats:
//// Without compiler optimization:
///// 6510ms elapsed for 100,000 runs = 0.065 ms/run
////// With compiler optimization:
/////// 4870ms elapsed for 100,000 runs = 0.049 ms/run
////////
///////// About 33 lines of C# code
//////////
public class Euler144 extends Sprite {
public function Euler144() {
var p:Point = new Point(1.4, -9.6);
run(p);
}
private function run(impactPoint:Point):void {
addDebug();
stage.addChild(_canvas);
_canvas.cacheAsBitmap = true;
_canvas.x = stage.stageWidth/2;
_canvas.y = stage.stageHeight/2;
drawEllipse(0,0,5,10);
A = new Point(0, 10.1);
B = impactPoint;
initLine(A);
drawLine(B);
slope = (A.y-B.y)/(A.x-B.x);
var count:int = 0;
this.addEventListener(Event.ENTER_FRAME, iter);
}
private function iter(e:Event):void {
for(var i:int = 0; i<2; i++) {
A = B;
slope = reflect(slope, -4*B.x/B.y);
var m:Number = B.y - B.x*slope;
B = intersection(slope, m, B);
drawLine(B);
count++;
clear();
out("Working...");
// Uncomment to stop when at hole
if( (B.x>0?B.x:-B.x) < 0.01 && B.y>0 ) {
this.removeEventListener(Event.ENTER_FRAME, iter);
clear();
out("Done!");
break;
}
}
//clear();
//out(count);
}
private var A:Point;
private var B:Point;
private var slope:Number;
private var count:int;
private function reflect(slope:Number, tangent:Number):Number {
return (slope*(tangent*tangent-1)+2*tangent)/(2*slope*tangent-tangent*tangent+1);
}
private function intersection(k:Number, m:Number, p:Point):Point {
var x1:Number = (-k*m + 2*Math.sqrt(25*k*k-m*m+100))/(4+k*k);
var x2:Number = (-k*m - 2*Math.sqrt(25*k*k-m*m+100))/(4+k*k);
var dx1:Number = p.x-x1;
var dx2:Number = p.x-x2;
dx1=dx1>0?dx1:-dx1;
dx2=dx2>0?dx2:-dx2;
if(dx1>dx2) // x1 correct
return new Point( x1, p.y+k*(x1-p.x) );
else
return new Point( x2, p.y+k*(x2-p.x) );
}
/////////// Drawing /////////////
private var _canvas:Sprite = new Sprite();
private var _scale:Number = 20;
private function drawEllipse(x:Number, y:Number, radX:int, radY:int):void {
_canvas.graphics.lineStyle(1);
x*=_scale;
y*=_scale;
radX*=_scale;
radY*=_scale;
_canvas.graphics.drawEllipse(x-radX, y-radY, radX*2, radY*2);
}
private function initLine(p:Point):void {
_canvas.graphics.moveTo(p.x*_scale, p.y*-_scale);
}
private function drawLine(p:Point):void {
_canvas.graphics.lineStyle(1, 0xDD0000, 0.4);
_canvas.graphics.lineTo(p.x*_scale, p.y*-_scale);
}
/////////////////////////////////
private var txt:TextField = new TextField();
private function addDebug():void {
stage.addChild(txt);
txt.width = 300;
txt.height = 600;
}
private function out(data:*):void {
txt.appendText(data+"\n");
}
private function clear():void {
txt.text = "";
}
}
}