Astar算法

最小堆

使用最小堆设计OpenList
具体实现

地图数据管理

格子对象

public abstract class BaseCell
{
    /// <summary>
    /// 位置信息
    /// </summary>
    public Vector pos { get; set; }
    /// <summary>
    /// 能否行走
    /// </summary>
    public bool walkable { get; set; }
    /// <summary>
    /// 簇
    /// </summary>
    internal Cluster cluster { get; set; }
    /// <summary>
    /// 邻接点对应的消耗
    /// </summary>
    public Dictionary<BaseCell, float> neighbours { get; set; }

    /// <summary>
    /// 计算邻接点
    /// </summary>
    /// <param name="map"></param>
    /// <param name="mode"></param>
    /// <param name="piercing"></param>
    public void CalculateNeighbours(IMap map, NeighbourMode mode, bool piercing)
    {
        List<Vector> expects = new List<Vector>();
        neighbours = new Dictionary<BaseCell, float>();
        BaseCell next;
        if (mode == NeighbourMode.Eight && piercing)
        {
            expects.Clear();
            foreach (var offset in Vector.four)
            {
                next = map[pos + offset];
                if (next == null || !next.walkable)
                {
                    expects.Add(offset);
                    if (Vector.dicExcept.TryGetValue(offset, out Vector[] expect))
                    {
                        expects.AddRange(expect);
                    }
                }
            }
        }

        foreach (var offset in Vector.Neighbours(mode))
        {
            if (expects.Contains(offset))
            {
                continue;
            }
            next = map[pos + offset];
            if (next != null && next.walkable)
            {
                neighbours.Add(next, Cost(next, offset));
            }
        }
    }

    /// <summary>
    /// 到邻接点的消耗
    /// </summary>
    /// <param name="offset">方向</param>
    /// <returns></returns>
    protected virtual float Cost(BaseCell next, Vector offset)
    {
        return offset.magnitude;
    }
}

K-Means聚类分析划分给地图划分簇

public struct Cluster
{
    public int index;
    /// <summary>
    /// 质心点
    /// </summary>
    public Vector centroid;
    public List<Vector> points;
    public float po;
    public float pt;
}

p o = n o ( 簇内障碍数 ) / N ( 簇内格子总数 ) p_o = n_o(簇内障碍数) / N (簇内格子总数) po=no(簇内障碍数)/N(簇内格子总数)
p t = n t ( 簇内无障碍条数 ) / ( L + D ) ( 簇内总条数 ) p_t = n_t(簇内无障碍条数) / (L + D)(簇内总条数) pt=nt(簇内无障碍条数)/(L+D)(簇内总条数)

K-Means分簇

private class Clusters
{
    private const int N = 128;
    private int m_Count;
    private Cluster[] m_Items;

    public Clusters(IMap map, int count)
    {
        m_Count = Initialize(map, count);

        KMeansPartition(map, 1);

        for (int i = 0; i < m_Count; i++)
        {
            m_Items[i].Finish(map);
        }
    }

    private int Initialize(IMap map, int count)
    {
        m_Items = new Astar.Cluster[count];

        int index = 0;
        BaseCell cell;
        for (int i = 0; i < map.rows; i++)
        {
            for (int j = 0; j < map.cols; j++)
            {
                cell = map[i, j];
                if (cell == null || !cell.walkable)
                {
                    m_Items[index] = new Astar.Cluster(index, new Vector(i, j));
                    index++;
                }

                if (index == count)
                {
                    return index;
                }
            }
        }
        return index;
    }

    private void KMeansPartition(IMap map, int depth)
    {
        for (int i = 0; i < m_Count; i++)
        {
            m_Items[i].Reset();
        }

        Vector v = Vector.zero;
        float min, d;
        int index;
        for (int x = 0; x < map.rows; x++)
        {
            v.x = x;
            for (int y = 0; y < map.cols; y++)
            {
                v.y = y;
                min = (v - m_Items[0].centroid).sqrMagnitude;
                index = 0;
                for (int i = 1; i < m_Count; i++)
                {
                    d = (v - m_Items[i].centroid).sqrMagnitude;
                    if (d < min)
                    {
                        min = d;
                        index = i;
                    }
                }

                m_Items[index].Add(v);
            }
        }

        bool changed = false;
        for (int i = 0; i < m_Count; i++)
        {
            if (m_Items[i].Update())
            {
                changed = true;
            }
        }

        if (changed && depth < N)
        {
            return;
        }

        KMeansPartition(map, depth + 1);
    }
}

评价函数设计

定义当前节点为n, 其父节点为p, 起始点为s, 终点为e

g ( n ) = g ( p ) + d i s t a n c e ( n , p ) g(n) = g(p) + distance(n,p) g(n)=g(p)+distance(n,p)
h ( n ) = c h e b y s h e v ( n , e ) h(n) = chebyshev(n,e) h(n)=chebyshev(n,e)
f ( n ) = ( p t + d s n / d s e ) ∗ g ( n ) + ( ( 1 − p o ) + e d n e / d s e f(n) = (p_t + d_sn/d_{se}) * g(n) + ((1-p_o) + e^{d_{ne}/d_{se}} f(n)=(pt+dsn/dse)g(n)+((1po)+edne/dse

/// <summary>
/// 契比雪夫(对角线)
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static float Chebyshev(Vector a, Vector b)
{
	float dx = Math.Abs(a.x - b.x);
	float dy = Math.Abs(a.y - b.y);
	if (dx > dy)
	{
		return D1 * (dx - dy) + D2 * dy;
	}
	else
	{
		return D1 * (dy - dx) + D2 * dx;
	}
}

Astar

protected override void ScanHandle()
{
    m_OpenList.Push(m_StartNode);
    Node current = null;
    while (m_OpenList.Count > 0)
    {
        if (!m_OpenList.TryPop(ref current))
        {
            break;
        }
        m_ClosedList[current.cell.pos] = current;
        if (current == m_EndNode)
        {
            m_Result.searched = true;
            break;
        }
        foreach (var it in current.cell.neighbours)
        {
            if (m_ClosedList.ContainsKey(it.Key.pos))
            {
                continue;
            }
            Node node = GetNode(it.Key);
            if (node.UpdateG(current, it.Value))
            {
                node.parent = current;
                m_OpenList.Push(node);
            }
        }
    }
}

源代码

GitHub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值