本文提供 Common/FindPath.cs 完整原始碼(優化前版本),供參考對比第 5 篇優化後版本。
using System;
using System.Drawing;
using System.Collections.Generic;
namespace Skyiv.Ben.PushBox.Common
{
static class FindPath
{
static Size[] offsets = { new Size(0, 1), new Size(1, 0), new Size(0, -1), new Size(-1, 0) };
static Direction[] directions = { Direction.South, Direction.East, Direction.North, Direction.West };
public static Queue Seek(ushort[,] map, Point from, Point to)
{
Queue moveQueue = new Queue();
int value;
if (Seek(map, to, out value))
{
Point here = from;
Point nbr = new Point();
for (value--; value > 0; value--)
{
for (int i = 0; i < offsets.Length; i++)
{
nbr = Fcl.Add(here, offsets[i]);
if (Block.Value(map[nbr.Y, nbr.X]) == value)
{
moveQueue.Enqueue(directions[i]);
break;
}
}
here = nbr;
}
}
Block.CleanAllMark(map);
return moveQueue;
}
static bool Seek(ushort[,] map, Point to, out int value)
{
Queue q = new Queue();
Block.Mark(ref map[to.Y, to.X], 1);
Point nbr = Point.Empty;
for (;;)
{
value = Block.Value(map[to.Y, to.X]) + 1;
for (int i = 0; i < offsets.Length; i++)
{
nbr = Fcl.Add(to, offsets[i]);
if (Block.IsMan(map[nbr.Y, nbr.X])) break;
if (Block.IsBlank(map[nbr.Y, nbr.X]))
{
Block.Mark(ref map[nbr.Y, nbr.X], value);
q.Enqueue(nbr);
}
}
if (Block.IsMan(map[nbr.Y, nbr.X])) break;
if (q.Count == 0) return false;
to = q.Dequeue();
}
return true;
}
}
}
Fcl.Add(Point, Size):座標加法(CF 相容)。Block.Mark/Value/CleanAllMark/IsMan/IsBlank:位元操作與狀態查詢。Direction:列舉 None, East, South, West, North (見 Step.cs)。| 項目 | 原始版本 | 優化後 (第 5 篇) |
|---|---|---|
| 地圖型別 | ushort[,] | byte[,] |
| 標記值範圍 | 1 ~ 8191 (距離+1) | 1, 2, 3 循環 |
| 最大搜尋距離 | 8191 步 | 無限制 |
| 記憶體佔用 | 基準 | 減半 |
| Mark/Value 實作 | 位移 3 bits,存完整距離 | 僅用 2 bits 存 1~3 |
此版本為演算法邏輯基準,理解其雙階段 BFS 流程後,再閱讀第 5 篇優化設計將更清晰。