/**
* 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);
}
}