ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【记录】使用 JavaScript(Typescript) 实现AStar 寻路算法

2021-06-20 12:35:30  阅读:1201  来源: 互联网

标签:map Typescript JavaScript pos AStarPos AStar let col row


再试着使用 JavaScript(Typescript) 实现AStar 寻路算法,在此记录一下。

export type CompareFn<T> = (a: T, b: T) => number;

export function appendToOrderList<T>(orderList: T[], item: T, compare: CompareFn<T>) {
    if (orderList.length > 0) {
        if (compare(item, orderList[0]) <= 0) {
            orderList.splice(0, 0, item);
        } else {
            let index;
            for (index = 0; index < orderList.length - 1; index++) {
                let compareToPrev = compare(item, orderList[index]);
                let compareToNext = compare(item, orderList[index + 1]);
                if (compareToPrev >= 0 && compareToNext <= 0) {
                    break;
                }
            }
            orderList.splice(index + 1, 0, item);
        }
    } else {
        orderList[0] = item;
    }
}

export type AStarPos = {
    row: number;
    col: number;

    step: number;      // 0
    searched: boolean; // false
    opened: boolean;   // false
    closed: boolean;   // false

    weight?: number;
    prev?: AStarPos;
}

export type AStarMap = AStarPos[][];

export const AStarConfig = {
    toStartWeight: 1,
    toEndWeight: 1
}

export function findRoad(gameMap: boolean[][], startPos: [number, number], endPos: [number, number]) {
    // create astar map
    let aStarMap: AStarMap = [];
    gameMap.forEach((row, rowIndex) => {
        aStarMap[rowIndex] = [];
        row.forEach((col, colIndex) => {
            let aStarPos: AStarPos = {

                row: rowIndex,
                col: colIndex,
                step: 0,

                searched: false, // false
                opened: false,   // false
                closed: !col,    // false
            };

            aStarMap[rowIndex][colIndex] = aStarPos;
        });
    });

    let aStarRoad = aStarFindRoad(aStarMap, startPos, endPos);

    return aStarRoad.map(aStarpos => [aStarpos.row, aStarpos.col]);
}

export function aStarFindRoad(map: AStarMap, [startRow, startCol]: [number, number], [endRow, endCol]: [number, number]) {
    let road: AStarPos[] = [];
    let openList: AStarPos[] = [];
    let testList: AStarPos[] = [];

    let startPos = map[startRow][startCol];
    let endPos = map[endRow][endCol];

    startPos.searched = true;
    startPos.opened = true;

    startPos.weight = calWeight(0, calDistance(startPos, endPos));

    openList.push(startPos);

    let testPos = openList.shift();
    while (testPos) {
        testPos.opened = false;
        testList.push(testPos);

        if (equalsPos(testPos, endPos)) {
            let roadPos: AStarPos | undefined = endPos;
            while (roadPos) {
                road.push(roadPos);
                roadPos = roadPos.prev;
            }
            return road.reverse();
        }

        let notSearchedPosList = getNotSearchedPosList(map, testPos);
        if (notSearchedPosList.length > 0) {
            for (let index = 0; index < notSearchedPosList.length; index++) {
                let notSearchedPos = notSearchedPosList[index];
                notSearchedPos.step = testPos.step + 1;
                notSearchedPos.weight = calWeight(notSearchedPos.step, calDistance(notSearchedPos, endPos));
                notSearchedPos.prev = testPos;
                addToOpenList(openList, notSearchedPos);
            };
        } else {
            testList.forEach(testPos => {
                testPos.closed = true;
            });
            testList = [];
        }

        testPos = openList.shift();
    }

    throw new Error("road not found");
}

function calWeight(toStart: number, toEnd: number) {
    return AStarConfig.toStartWeight * toStart + AStarConfig.toEndWeight * toEnd;
}

function calDistance(pos0: AStarPos, pos1: AStarPos) {
    let dRow = pos0.row - pos1.row;
    let dCol = pos0.col - pos1.col;
    return Math.abs(dRow) + Math.abs(dCol);
}

function getNotSearchedPosList(map: AStarMap, pos: AStarPos) {
    let aroundPosList: [number, number][] = [
        [pos.row + 1, pos.col],
        [pos.row - 1, pos.col],
        [pos.row, pos.col + 1],
        [pos.row, pos.col - 1],

        [pos.row + 1, pos.col + 1],
        [pos.row + 1, pos.col - 1],
        [pos.row - 1, pos.col + 1],
        [pos.row - 1, pos.col - 1],
    ];

    let notSearchedPosList: AStarPos[] = [];

    aroundPosList.forEach(aroundPos => {
        let [row, col] = aroundPos;
        if ((row >= 0 && row < map.length) &&
            (col >= 0 && col < map[row].length) &&
            (!map[row][col].searched) &&
            (!map[row][col].opened) &&
            (!map[row][col].closed)) {
            map[row][col].searched = true;
            notSearchedPosList.push(map[row][col]);
        }
    });

    return notSearchedPosList;
}

function addToOpenList(openList: AStarPos[], pos: AStarPos) {
    pos.opened = true;
    appendToOrderList(openList, pos, (pos0, pos1) => {
        if (pos0.weight !== undefined &&
            pos1.weight !== undefined) {
            return pos0.weight - pos1.weight;
        }
        return 0;
    });
}

function equalsPos(pos0: AStarPos, pos1: AStarPos) {
    return pos0.row === pos1.row && pos0.col === pos1.col;
}

 

标签:map,Typescript,JavaScript,pos,AStarPos,AStar,let,col,row
来源: https://www.cnblogs.com/bajiaoyugege/p/14906463.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有