package hongwei.game.arithmetics
{
import hongwei.game.map.IMapData;
public final class AStar
{
private const COST_STRAIGHT:int = 5;
private const COST_DIAGONAL:int = 7;
private const NOTE_ID:int = 0;
private const NOTE_OPEN:int = 1;
private const NOTE_CLOSED:int = 2;
private var oId:int;
private var oCount:int;
private var xList:Array;
private var yList:Array;
private var oList:Array;
private var fList:Array;
private var psList:Array;
private var mcList:Array;
private var noteMap:Array;
public function AStar(mapData:IMapData)
{
_mapData = mapData;
}
private var _maxTry:int = 500;
public function get maxTry():int
{
return _maxTry;
}
public function set maxTry(value:int):void
{
_maxTry = value;
}
private var _mapData:IMapData;
public function get mapData():IMapData
{
return _mapData;
}
public function set mapData(value:IMapData):void
{
_mapData = value;
}
public function find(startX:int, startY:int, endX:int, endY:int):Array
{
initLists();
oId = -1;
oCount = 0;
openNote(startX, startY, 0, 0, 0);
var currentTry:int = 0;
var currentId:int;
var currentNoteX:int;
var currentNoteY:int;
var aroundNotes:Array;
var checkingId:int;
var cost:int;
var score:int;
while (0 < oCount)
{
if (++currentTry > _maxTry)
{
destroyLists();
return null;
}
currentId = oList[0];
currentNoteX = xList[currentId];
currentNoteY = yList[currentId];
closeNote(currentId);
if (currentNoteX == endX && currentNoteY == endY)
return getPath(startX, startY, currentId);
aroundNotes = getArounds(currentNoteX, currentNoteY);
for each (var note:Array in aroundNotes)
{
cost = mcList[currentId]
+ (note[0] == currentNoteX || note[1] == currentNoteY ? COST_STRAIGHT : COST_DIAGONAL)
* _mapData.getCost(currentNoteX, currentNoteY, note[0], note[1]);
score = cost + (Math.abs(endX - note[0]) + Math.abs(endY - note[1])) * COST_STRAIGHT;
if (isOpen(note[0], note[1]))
{
checkingId = noteMap[note[1]][note[0]][NOTE_ID];
if (cost < mcList[checkingId])
{
fList[checkingId] = currentId;
psList[checkingId] = score;
mcList[checkingId] = cost;
aheadNote(getIndex(checkingId));
}
}
else
openNote(note[0], note[1], score, cost, currentId);
}
}
destroyLists();
return null;
}
private function openNote(x:int, y:int, score:int, cost:int, fatherId:int):void
{
oId++;
oCount++;
if (null == noteMap[y])
noteMap[y] = [];
noteMap[y][x] = [];
noteMap[y][x][NOTE_ID] = oId;
noteMap[y][x][NOTE_OPEN] = true;
xList.push(x);
yList.push(y);
oList.push(oId);
fList.push(fatherId);
psList.push(score);
mcList.push(cost);
aheadNote(oCount);
}
private function closeNote(id:int):void
{
oCount--;
var noteX:int = xList[id];
var noteY:int = yList[id];
noteMap[noteY][noteX][NOTE_OPEN] = false;
noteMap[noteY][noteX][NOTE_CLOSED] = true;
if (0 >= oCount)
{
oCount = 0;
oList = [];
return;
}
oList[0] = oList.pop();
backNote();
}
private function aheadNote(index:int):void
{
var fIndex:int;
var change:int;
while (index > 1)
{
fIndex = Math.floor(index / 2);
if (getScore(index) < getScore(fIndex))
{
change = oList[index - 1];
oList[index - 1] = oList[fIndex - 1];
oList[fIndex - 1] = change;
index = fIndex;
}
else
break;
}
}
private function backNote():void
{
var cIndex:int = 1;
var tIndex:int;
var change:int;
while (true)
{
tIndex = cIndex;
if (2 * tIndex <= oCount)
{
if (getScore(cIndex) > getScore(2 * tIndex))
cIndex = 2 * tIndex;
if (2 * tIndex + 1 <= oCount &&
getScore(cIndex) > getScore(2 * tIndex + 1))
cIndex = 2 * tIndex + 1;
}
if (tIndex == cIndex)
break;
else
{
change = oList[tIndex - 1];
oList[tIndex - 1] = oList[cIndex - 1];
oList[cIndex - 1] = change;
}
}
}
private function getArounds(x:int, y:int):Array
{
var r:Array = [];
var checkX:int;
var checkY:int;
var canDiagonal:Boolean;
checkX = x + 1;
checkY = y;
var canRight:Boolean = _mapData.isBlock(x, y, checkX, checkY);
if (canRight && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x;
checkY = y + 1;
var canDown:Boolean = _mapData.isBlock(x, y, checkX, checkY);
if (canDown && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x - 1;
checkY = y;
var canLeft:Boolean = _mapData.isBlock(x, y, checkX, checkY);
if (canLeft && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x;
checkY = y - 1;
var canUp:Boolean = _mapData.isBlock(x, y, checkX, checkY);
if (canUp && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x + 1;
checkY = y + 1;
canDiagonal = _mapData.isBlock(x, y, checkX, checkY);
if (canDiagonal && canRight && canDown && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x - 1;
checkY = y + 1;
canDiagonal = _mapData.isBlock(x, y, checkX, checkY);
if (canDiagonal && canLeft && canDown && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x - 1;
checkY = y - 1;
canDiagonal = _mapData.isBlock(x, y, checkX, checkY);
if (canDiagonal && canLeft && canUp && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
checkX = x + 1;
checkY = y - 1;
canDiagonal = _mapData.isBlock(x, y, checkX, checkY);
if (canDiagonal && canRight && canUp && !isClosed(checkX, checkY))
r.push([checkX, checkY]);
return r;
}
private function getIndex(id:int):int
{
var r:int = 1;
for each (var tId:int in oList)
{
if (id == tId)
return r;
r++;
}
return -1;
}
private function getPath(startX:int, startY:int, endId:int):Array
{
var r:Array = [];
var noteX:int = xList[endId];
var noteY:int = yList[endId];
while (noteX != startX || noteY != startY)
{
r.unshift([noteX, noteY]);
endId = fList[endId];
noteX = xList[endId];
noteY = yList[endId];
}
r.unshift([startX, startY]);
destroyLists();
return r;
}
private function getScore(index:int):int
{
return psList[oList[index - 1]];
}
private function isOpen(x:int, y:int):Boolean
{
if (null == noteMap[y]) return false;
if (null == noteMap[y][x]) return false;
return noteMap[y][x][NOTE_OPEN];
}
private function isClosed(x:int, y:int):Boolean
{
if (null == noteMap[y]) return false;
if (null == noteMap[y][x]) return false;
return noteMap[y][x][NOTE_CLOSED];
}
private function initLists():void
{
xList = [];
yList = [];
oList = [];
fList = [];
psList = [];
mcList = [];
noteMap = [];
}
private function destroyLists():void
{
xList = null;
yList = null;
oList = null;
fList = null;
psList = null;
mcList = null;
noteMap = null;
}
}
}
package hongwei.game.map
{
public interface IMapData
{
function getCost(startX:int, startY:int, endX:int, endY:int):int;
function isBlock(startX:int, startY:int, endX:int, endY:int):Boolean;
}
}
2009年3月26日星期四
支持8方向的AStar寻路AS3算法
2009年3月21日星期六
AS3中操作Telnet的类
package hongwei.net
{
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
[Event(name="close", type="flash.events.Event")]
[Event(name="connect", type="flash.events.Event")]
[Event(name="data", type="flash.events.DataEvent")]
[Event(name="ioError", type="flash.events.IOErrorEvent")]
[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
public class TelnetSocket extends EventDispatcher
{
private static const NUL:int = 0x00;
private static const BEL:int = 0x07;
private static const BS:int = 0x08;
private static const HT:int = 0x09;
private static const LF:int = 0x0A;
private static const FF:int = 0x0C;
private static const CR:int = 0x0D;
private static const SE:int = 0xF0;
private static const NOP:int = 0xF1;
private static const DM:int = 0xF2;
private static const BRK:int = 0xF3;
private static const IP:int = 0xF4;
private static const AO:int = 0xF5;
private static const AYT:int = 0xF6;
private static const EC:int = 0xF7;
private static const EL:int = 0xF8;
private static const GA:int = 0xF9;
private static const SB:int = 0xFA;
private static const WILL:int = 0xFB;
private static const WONT:int = 0xFC;
private static const DO:int = 0xFD;
private static const DONT:int = 0xFE;
private static const IAC:int = 0xFF;
public var charSet:String = "utf-8";
private var _socket:Socket;
private var _state:int;
public function TelnetSocket(host:String=null, port:int=0)
{
_socket = new Socket(host, port);
_socket.addEventListener(Event.CLOSE, _socket_close);
_socket.addEventListener(Event.CONNECT, _socket_connect);
_socket.addEventListener(IOErrorEvent.IO_ERROR, _socket_ioError);
_socket.addEventListener(ProgressEvent.SOCKET_DATA, _socket_socketData);
_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _socket_securityError);
_state = 0;
}
public function get connected():Boolean
{
return _socket.connected;
}
public function close():void
{
_socket.close();
}
public function connect(host:String, port:int):void
{
_socket.connect(host, port);
}
public function send(value:String):void
{
_socket.writeMultiByte(value, charSet);
_socket.flush();
}
private function _socket_close(e:Event):void
{
dispatchEvent(e);
}
private function _socket_connect(e:Event):void
{
dispatchEvent(e);
}
private function _socket_ioError(e:IOErrorEvent):void
{
dispatchEvent(e);
}
private function _socket_socketData(e:ProgressEvent):void
{
var n:int = _socket.bytesAvailable;
var buffer:ByteArray = new ByteArray();
while (0 <= --n)
{
var b:int = _socket.readUnsignedByte();
switch (_state)
{
case 0:
if (IAC == b)
{
_state = 1;
}
else if (CR != b)
{
buffer.writeByte(b);
}
break;
case 1:
_state = DO == b ? 2 : 0;
break;
case 2:
_socket.writeByte(IAC);
_socket.writeByte(WONT);
_socket.writeByte(b);
_socket.flush();
_state = 0;
break;
}
}
buffer.position = 0;
dispatchEvent(new DataEvent(DataEvent.DATA, false, false, buffer.readMultiByte(buffer.length, charSet)));
}
private function _socket_securityError(e:SecurityErrorEvent):void
{
dispatchEvent(e);
}
}
}
订阅:
博文 (Atom)