JavaScript-尝试根据距离查找方向

时间:2019-04-26 14:34:32

标签: javascript

我正在尝试使用同时用作输入字段和游戏显示的输入框来创建一个简单的寻宝游戏。游戏中有一个英雄-h和多个杀手-k,它们由计算机控制,试图杀死该英雄。

这是我的一个示例板:

example board

到目前为止,我已经对一些if语句进行了硬编码,以检查英雄和给定的杀手的坐标(基于他们当前所在的输入框),以确定杀手应该以哪种方式移动(上,下,右) ,左和对角线)。但是,它并不总是能找到最佳的方向。

if (killerX < heroX) {
  if (killerY < heroY) {
    console.log("move down andright");
  } else if (killerY > heroY) {
    console.log("move up and right");
  }
}

我当时正在考虑使用Dijkstra的算法,但我不知道如何针对给定的问题实现该算法。我正在寻找一种更有效的替代方法,以发现凶手必须采取哪种行动才能更接近英雄。

3 个答案:

答案 0 :(得分:0)

也许是这样的:

function getMove(killerX, killerY, heroX, heroY) {
    let move = [];
    if (killerY < heroY) {
        move.push("up");
    } else if (killerY > heroY) {
        move.push("down");
    }
    if (killerX < heroX) {
        move.push("left");
    } else if (killerX > heroX) {
        move.push("right");
    }
    if (move.length) {
        return "move " + move.join(" and ");
    }
    return "you've got them!";
}

使用数组的原因是您可能不需要始终同时垂直和水平移动。

在那种情况下,我假设朝着零的方向是“上”和“左”(这与您的问题不太匹配,但是我认为您的文字只是一个例子)。

带有测试的实时示例:

function getMove(killerX, killerY, heroX, heroY) {
    let move = [];
    if (killerY < heroY) {
        move.push("up");
    } else if (killerY > heroY) {
        move.push("down");
    }
    if (killerX < heroX) {
        move.push("left");
    } else if (killerX > heroX) {
        move.push("right");
    }
    if (move.length) {
        return "move " + move.join(" and ");
    }
    return "you've got them!";
}
function test(killerX, killerY, heroX, heroY, expect) {
    let move = getMove(killerX, killerY, heroX, heroY);
    console.log(`(${killerX}, ${killerY}), {${heroX}, ${heroY}): ${move} <== ${move === expect ? "OK" : "ERROR, should be: " + expect}`);
}
test(3, 3, 3, 4, "move up");
test(3, 3, 1, 4, "move up and right");
test(3, 3, 1, 3, "move right");
test(3, 3, 1, 1, "move down and right");
test(3, 3, 3, 1, "move down");
test(3, 3, 4, 1, "move down and left");
test(3, 3, 4, 3, "move left");
test(3, 3, 4, 4, "move up and left");
.as-console-wrapper {
  max-height: 100% !important;
}

答案 1 :(得分:0)

如果您的地图上没有任何墙,那是一个非常琐碎的练习!

您的代码中有2个问题。首先,您不处理案件killerX > heroX,其次,您必须一步步移动,而不是2步2步。

let diffX = killerX - playerX;
let diffY = killerY - playerY;

if(Math.abs(diffX) > Math.abs(diffY)) {
  if(diffX>0) {
    console.log('move left');
  }
  else {
    console.log('move right');
  }
} else {
  if(diffY>0) {
    console.log('move up');
  } else {
    console.log('move down');
  }
}

答案 2 :(得分:0)

为此,我忍不住要编写一个Dijkstra实现。对于您的问题,这可能太大了。

/**
 * Set up and return the game board, which is an array with one object per field on the board
 */
function buildBoard(sizeX, sizeY) {
    const board = [];

    for (let y = 0; y < sizeY; y++) {
        for (let x = 0; x < sizeX; x++) {
            const field = {x, y, distance: Number.MAX_VALUE, weight: 1, predecessor: null};
            board.push(field);
        }
    }

    return board;
}

/**
 * Run Dijkstra to find the closest path on the playing field from point a to point b
 */
function getPathOnBoardFromAToB(board, a, b) {
    const fieldAtA = board.find(node => node.x === a.x && node.y === a.y);
    const fieldAtB = board.find(node => node.x === b.x && node.y === b.y);

    fieldAtA.distance = 0;

    const unvisitedFields = [...board];

    while (unvisitedFields.length > 0) {
        const currentField = unvisitedFields.sort((n1, n2) => n1.distance > n2.distance ? 1 : -1)[0];
        unvisitedFields.splice(unvisitedFields.indexOf(currentField), 1);

        // all fields that are up to 1 field away in both X and Y directions are neighors that can be visited from
        // the current field
        const neighbors = unvisitedFields.filter(field => Math.abs(field.x - currentField.x) <= 1 && Math.abs(field.y - currentField.y) <= 1);

        // see if any of the neighbors is reachable more easily via the current field than before
        for (const neighbor of neighbors) {
            const distanceViaCurrentField = currentField.distance + neighbor.weight;
            if (distanceViaCurrentField < neighbor.distance) {
                // relax
                neighbor.distance = distanceViaCurrentField;
                neighbor.predecessor = currentField;
            }
        }

    }

    return buildPathViaPredecessors(fieldAtB);
}

/**
 * Called with the target field once Dijkstra has run, generates an array that contains the field-by-field
 * path from the predecessors set
 */
function buildPathViaPredecessors(targetField) {
    let currentField = targetField;
    const path = [];
    while (currentField != null) {
        path.push(currentField);
        currentField = currentField.predecessor;
    }
    return path;
}

function renderPath(path) {
    console.log(path.reverse().map(field => `[ ${field.x}, ${field.y} ]`).join(' -> '));
}

const killer = {x: 8, y: 7};
const hero = {x: 0, y: 2};

const board = buildBoard(10, 10);
const bestWay = getPathOnBoardFromAToB(board, killer, hero);

renderPath(bestWay);