アミダくじ

by n0wri
あみだ、阿弥陀、あみだくじ,amida lotto
♥0 | Line 534 | Modified 2011-09-20 02:27:40 | MIT License
play

ActionScript3 source code

/**
 * Copyright n0wri ( http://wonderfl.net/user/n0wri )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/64Ep
 */

// あみだくじ
//ver 1.0

package
{
	import flash.display.Sprite;

	public class Amida extends Sprite
	{
		public function Amida()
		{
			var amida:AmidaView = new AmidaView();
			addChild(amida);
		}
	}
}
import flash.geom.Point;
import frocessing.display.F5MovieClip2DBmp;
class AmidaView extends F5MovieClip2DBmp
{
	private static const SPEED:Number=0.01;
	private static const Y:uint = 60;
	private static const W:uint = 400;
	private static const X:uint = uint(W*1/4);
	private static const H:uint = 400;
	private var route:Array;
	private var current:uint;
	
	public function draw():void
	{
		var col:uint = (route[current]as PointVO).col;
		var val:Number = (route[current]as PointVO).val;
		
		circle(W*(col+1)/4, val*(H-Y)+Y, 3);
		current++;
		if(current>=route.length)
		{
			noLoop();
		}
	}
	
	public function AmidaView() 
	{
		noLoop();
		current=0;
		var i : int;
		
		
		//初期設定
		size(465,465);
		background(0xeeeeee);
		
		// 縦線view つくる
		stroke(0x000000);
		lineStyle(5);
		
		line( X, Y, W*1/4, H );
		line( X*2,  Y, W*2/4,  H );
		line( X*3, Y, W*3/4, H );
		line( W,  Y, W,  H );
		
		// amidaつくる
		var amida:AmidaBase = new AmidaBase( 0, 0,
		[
			0.05,
			0.1,
			0.25,
			0.35,
			0.45,
			0.55,
			0.65,
			0.75,
			0.8,
			0.9
		],
		[
			0.17,
			0.3,
			0.5,
			0.52,
			0.57,
			0.67,
			0.77,
			0.87,
			0.95
		],
		[
			0.2,
			0.24,
			0.32,
			0.4,
			0.45,
			0.59,
			0.62,
			0.75,
			0.82
		],
		[
			0.16,
			0.27,
			0.3,
			0.42,
			0.48,
			0.5,
			0.7,
			0.88,
			0.9
		]
		);		
		
		// 横線view つくる
		for (i=0; i<amida.holizonalLineList.length; i++) 
		{
			var pList:Array = amida.holizonalLineList[i];
			var p1:PointVO = pList[0];
			var p2:PointVO = pList[1];
			lineStyle(5, 0x000000);
			line((p1.col+1)*X, p1.val*(H-Y)+Y, (p2.col+1)*X, p2.val*(H-Y)+Y);
		};
		
		//分岐ポイントview つくる
		for(i=0; i < amida.map.length; i++) 
		{
			var vo:PointVO = amida.map[i];
			var _w1:Number = W*(vo.col+1)/4;
			lineStyle(0);
			beginFill(0x00ff00);
			circle(_w1, vo.val*(H-Y)+Y, 5);
		};
		
		//スタート、ゴールポイントview つくる
		beginFill(0xff0000);
		circle(W*(amida.departureIndex+1)/4, Y, 5);
		circle(W*(amida.arrivalIndex+1)/4, H, 5);
		route = amida.getRouteList();
		beginFill(0xff00ff);
		loop();

	}
	
	
	
}

class AmidaBase
{
	//---------------------------------------------------------------------------------------------------------------------------------------------
	// Public Properties
	//---------------------------------------------------------------------------------------------------------------------------------------------
	
	
	//---------------------------------------------------------------------------------------------------------------------------------------------
	// Internal Properties
	//---------------------------------------------------------------------------------------------------------------------------------------------
	private static const TIMEOUT_COUNT:uint=100;
	private static const MIN_HORIZONAL_PER_ONE_ROW:uint=2;
	private var colLength:uint;
	private var rowLength:Array;
	private var _map:Array;
	private var canPresetList:Array;
	private var _departureIndex:uint;
	private var _arrivalIndex:uint;
	private var _holizonalLineList:Array;
	
	
	//---------------------------------------------------------------------------------------------------------------------------------------------
	// Public Methods
	//---------------------------------------------------------------------------------------------------------------------------------------------
	public function AmidaBase( departureIndex:uint, arrivalIndex:uint, ...pointList:Array )
	{
		_departureIndex = departureIndex;
		_arrivalIndex = arrivalIndex;
		createMap(pointList);
		var tryNum:uint = 0;
		
		while(tryNum<TIMEOUT_COUNT)
		{
			createHolizonalLine();
			if(tryNum+1 != TIMEOUT_COUNT)
			{
				if(editHolizonalLineFromDepartureToArrival())
				{
					break;
				};
			}
			else
			{
				if(editHolizonalLineFromDepartureToArrival(true))
				{
					break;
				};
			};
			tryNum++;
			trace("tryNum:",tryNum);
		};
	}

	
 
	
	
	public function getRouteList():Array
	{
		var routeList:Array=[];
		var holizonalLineList:Array=_holizonalLineList.concat();
		var deleteHorizonalLine:Function = function(index:uint):void
		{
			holizonalLineList.splice(index,1);
		};
		
		var getTangentHorizonalLineVO:Function = function(vo:PointVO):PointVO
		{
			var len:uint = holizonalLineList.length;
			for (var i:int=0; i<len; i++) 
			{
				var list:Array = holizonalLineList[i];
				
				var vo1:PointVO = list[0];
				var vo2:PointVO = list[1];
				var j:uint=0;
				if(vo1.col==vo.col&&vo1.row==vo.row)
				{
					j = j ^ 1;
					deleteHorizonalLine(i);
					return list[j];
				}
				else if(vo2.col==vo.col&&vo2.row==vo.row)
				{
					deleteHorizonalLine(i);
					return list[j];
				};
			};
			return null;
		};
		
		var hasNext:Function = function():Boolean
		{
			var vo:PointVO = routeList[routeList.length-1]as PointVO;
			return vo.val<1;
		};
		var getNext:Function =function():PointVO
		{
			var vo:PointVO = routeList[routeList.length-1]as PointVO;
			var vo2:PointVO = getTangentHorizonalLineVO(vo);
			if(!vo2)
			{
				return getVoByMatrix(vo.col, vo.row+1);
			};
			return vo2;
		};
		
		routeList.push(getVoByMatrix(_departureIndex, 0));		
		
		while(hasNext()) 
		{
			routeList.push(getNext());
		};
		
		return routeList;
	}

	
	// getter setter
	public function get departureIndex():uint
	{
		return _departureIndex;
	}
	
	public function get arrivalIndex() : uint
	{
		return _arrivalIndex;
	}

	public function get holizonalLineList():Array
	{
		return _holizonalLineList;
	}

	public function get map():Array
	{
		return _map;
	}
	
	//---------------------------------------------------------------------------------------------------------------------------------------------
	// Internal Methods
	//---------------------------------------------------------------------------------------------------------------------------------------------
	private function createMap(pointList:Array):void
	{
		rowLength=[];
		canPresetList=[];
		_map=[];
		for(var i:int=0; i < pointList.length; i++) 
		{
			_map.push(new PointVO(i, 0, 0));
			var rows:Array = pointList[i];
			for (var j : int = 0; j < rows.length; j++) 
			{
				var vo:PointVO = new PointVO(i, j+1, rows[j]);
				_map.push(vo);
				canPresetList.push(vo);
			};
			_map.push(new PointVO(i, rows.length+1, 1));
			rowLength[i] = rows.length+2;
		};
		colLength = pointList.length;
	}
 
	private function createHolizonalLine():void
	{
		// <--- util
		var p:Function = function(x:Number, y:Number):Point
		{
			return new Point(x, y);
		};
		
		var isUsedVO:Function = function(vo:PointVO):Boolean
		{
			for(var i:int=0; i<_holizonalLineList.length; i++) 
			{
				var vo1:PointVO = _holizonalLineList[i][0]as PointVO;
				var vo2:PointVO = _holizonalLineList[i][1]as PointVO;
				if(vo===vo1 || vo===vo2)
				{
					return true;
				};
			};
			return false;
		};
		
		var deleteVoByMatrix:Function = function(col:uint, row:uint, ar:Array = null):void
		{
			ar = (ar)? ar:_canPresetList;
			for(var i:int=0; i<ar.length; i++) 
			{
				var vo:PointVO = ar[i];
				if(vo.col==col && vo.row==row)
				{
					ar.splice(i, 1);
					break; 
				};
			};
		};
		
		var getVosByMatrix:Function = function(col:int=-1, row:int=-1, ar:Array = null):Array
		{
			ar = (ar)? ar:canPresetList;
			var _ar:Array=[];
			if(col==-1&&row==-1)
			{
//				try
//				{
					throw new ArgumentError("col か row どちらかは必ず指定する事");
//				}catch(e:ArgumentError){trace(e);return;};
			
			}
			else if(col!=-1&&row!=-1)
			{
				trace("リストそのまま返り値");
				return ar;
			}
			else
			{
				for(var i:int=0; i<ar.length; i++) 
				{
					var vo:PointVO = ar[i];
					if((col==vo.col&&row==-1) || (row==vo.row&&col==-1))
					{
						_ar.push(vo);
					};
				};
			}
			return _ar;
		};
		
		var getArrivalCandidateVoList:Function = function(target:PointVO, arrivalXList:Array):Array
		{
			var candidateVoList:Array = [];
			var targetY:Number = target.val;
			for (var i :int = 0; i < arrivalXList.length; i++) 
			{
				var ar:Array = getVosByMatrix(arrivalXList[i]);
				var currentMaxVO:PointVO=null;
				var currentMinVO:PointVO=null; 
				for(var j:int=0; j<ar.length; j++) 
				{
					var vo:PointVO = ar[j]as PointVO;
					if(isCross(target,vo))
					{
						continue;
					};
					if(vo.val > targetY)
					{
						if(!currentMaxVO || currentMaxVO.val>vo.val)
						{
							currentMaxVO = vo;
						};
					}
					else if(vo.val < targetY)
					{
						if(!currentMinVO || currentMinVO.val<vo.val)
						{
							currentMinVO = vo;
						};
					};
				};
				if(currentMaxVO)
				{
					if(!isUsedVO(currentMaxVO))candidateVoList.push(currentMaxVO);
				}
				if(currentMinVO)
				{
					if(!isUsedVO(currentMinVO))candidateVoList.push(currentMinVO);
				}
			};
			return candidateVoList;
		};
		// util --->		
		var getArrivalPoint:Function = function(target:PointVO, ...arrivalXList:Array):PointVO
		{
			//端側だけ横線が多くなる対策
//			if(arrivalXList.length==1)
//			{
//				return null;
//				if(Math.random()>0.1)return null;
//			};
			var candidateVoList:Array = getArrivalCandidateVoList( target, arrivalXList );
			var arrivalPoint:PointVO = candidateVoList[uint(Math.random()*candidateVoList.length)];
			if(arrivalPoint)deleteVoByMatrix(arrivalPoint.col, arrivalPoint.row);
			return arrivalPoint;
		};
		
		var isCross:Function = function(vo1:PointVO, vo2:PointVO):Boolean
		{
			for(var i:int=0; i<_holizonalLineList.length; i++) 
			{
				var vo3:PointVO = _holizonalLineList[i][0]as PointVO;
				var vo4:PointVO = _holizonalLineList[i][1]as PointVO;
				if(Line.isCross(p(vo1.col,vo1.val), p(vo2.col,vo2.val), p(vo3.col,vo3.val), p(vo4.col,vo4.val)))
				{
					return true;
				};
			};
			return false;
		};
		var _canPresetList:Array = canPresetList.concat();
		_holizonalLineList=[];
		while(_canPresetList.length)
		{
			//ランダムにポイントを決める
			var vo:PointVO=_canPresetList.splice(uint(_canPresetList.length*Math.random()),1)[0];
			var x:uint = vo.col;
			//到達点を決める
			var arivalPt:PointVO;
			if(x==0)
			{
				arivalPt = getArrivalPoint(vo, x+1);
			}
			else if(x==colLength-1)
			{ 
				arivalPt = getArrivalPoint(vo, x-1 );
			}
			else
			{
				arivalPt = getArrivalPoint(vo, x-1, x+1 );
			};
			if(arivalPt)
			{
				_holizonalLineList.push([vo, arivalPt]);
			};
		};
	}
	
	private function editHolizonalLineFromDepartureToArrival(isHorizonalMax:Boolean=false):Boolean
	{
		var tryTime:uint=0;
		var cloneHolizonalAr:Array = _holizonalLineList.concat();
		var thretheld:uint = uint(cloneHolizonalAr.length*0.7);
		var holizonalLineListContainer:Array =[];
		
		var isAdaptHolizonalLineSpectrum:Function = function():Boolean
		{
			var ar:Array = getHolozonalLineListPerRow();
			for (var i : int = 0; i < ar.length; i++) 
			{
				if(!ar[i])
				{
					return false;
					break;
				}
				else if(ar[i].length<MIN_HORIZONAL_PER_ONE_ROW)
				{
					return false;
					break;
				};
			};
			
			return true;
		};
		var isArrival:Function = function():Boolean
		{
			var ar:Array = getRouteList();
			var vo:PointVO = ar[ar.length-1];
			if(vo.col==_arrivalIndex){return true;};
			return false;
		};
		var tryEdit:Function = function():Boolean
		{
			var _cloneHolizonalAr:Array= cloneHolizonalAr.concat();
			while(_cloneHolizonalAr.length-thretheld)
			{
				_cloneHolizonalAr.shift();
				holizonalLineListContainer.push(_cloneHolizonalAr.concat());
			};
			while(holizonalLineListContainer.length)
			{
				_holizonalLineList = holizonalLineListContainer.splice(uint(holizonalLineListContainer.length*Math.random()), 1)[0];
				if(isArrival()&& isAdaptHolizonalLineSpectrum())
				{
					return true;
					break;
				};
			};
			holizonalLineListContainer=[];
			_holizonalLineList = cloneHolizonalAr.concat();
			tryTime++;
			return false;
		};
		//最初に試行する
		var bool:Boolean = tryEdit();
		if(bool){return true;};
		if(!isHorizonalMax)
		{
			return false;
		};
		//ダメだった場合の試行。横線の数の幅を最大に
		thretheld=0;
		return tryEdit();
		
//		//初期状態で適合する場合
//		if(isArrival())
//		{
//			if(Math.random()>0.7){return true;};
//		};
//		//最初に試行する
//		while(tryTime<TIMEOUT_COUNT)
//		{
//			if(tryEdit())
//			{
//				return true;
//			};
//		};
//		if(!isHorizonalMax)
//		{
//			return false;
//		};
//		//ダメだった場合の試行。横線の数の幅を最大に
//		thretheld=0;
//		tryTime=0;
//		while(tryTime<TIMEOUT_COUNT)
//		{
//			if(tryEdit())
//			{
//				return true;
//			};
//		};
//		return false;
	}
	
	//util
	private function getVoByMatrix(col:int, row:int, ar:Array = null):PointVO
	{
		ar =(ar)? ar:_map;
		for(var i:int=0; i<ar.length; i++) 
		{
			var vo:PointVO = ar[i];
			
			if(vo.col==col && vo.row==row)
			{
				return vo;
			};
		};
		return null;
	};
	private function getHolozonalLineListPerRow():Array
	{
		var ar:Array=[];
		for(var i : int = 0; i < _holizonalLineList.length; i++) 
		{
			var line:Array = _holizonalLineList[i];
//			trace(0,line[0]);
//			trace(1,line[1]);
			var col:uint = Math.min((line[0]as PointVO).col,(line[1]as PointVO).col);
			if(ar[col]==undefined || ar[col]==null)ar[col]=[];
			ar[col].push(line);
		}
		return ar;
	};
}

class PointVO
{
	private var _col:uint;
	private var _row:uint;
	private var _val:Number;
	public function PointVO(col:uint, row:uint, val:Number) 
	{
		_col = col;
		_row = row;
		_val = val;
	}
	
	public function dump():String 
	{
		return new String(
			"col:" + _col + "\n" + 
			"row:" + _row + "\n" + 
			"val:" + _val + "\n"
		);
	}

	public function get col():uint
	{
		return _col;
	}

	public function get row():uint
	{
		return _row;
	}

	public function get val():Number
	{
		return _val;
	}
}

class Line
{
        public static function crossPoint(p1:Point, p2:Point, p3:Point, p4:Point):Point 
		{
                var a:Point = new Point(p2.x - p1.x, p2.y- p1.y);
                var b:Point = new Point(p4.x - p3.x, p4.y- p3.y);
                var c:Point = new Point(p3.x - p1.x, p3.y- p1.y);
                
                var result:Point = new Point();
                
                var cross_b_c:Number = b.x*c.y - b.y*c.x;
                var cross_b_a:Number = b.x*a.y - b.y*a.x;
                
                if(cross_b_a == 0)
                return null;
                
                result.x = p1.x + a.x * cross_b_c / cross_b_a;
                result.y = p1.y + a.y * cross_b_c / cross_b_a;
                
                return result;
        }
		
		public static function isCross(p1:Point, p2:Point, p3:Point, p4:Point):Boolean
		{
			var p:Point = crossPoint(p1,p2,p3,p4);
			return (p != null &&
			(p.x - p3.x) * (p.x - p4.x) + (p.y - p3.y) * (p.y - p4.y) < 0) &&
			((p.x - p1.x) * (p.x - p2.x) + (p.y - p1.y) * (p.y - p2.y) < 0);
		}
}