矩阵中两个单元格之间的最短路径
Shortest path between two cells in a matrix
我有一个二维数组,用于表示角色在游戏中的位置,我将其称为网格。网格是一个 5x5 大小的网格。并非网格上的所有 tiles/locations 都是角色可以穿越的可行位置。在示例图像中,您可以看到其中三个位置是水而不是陆地,表示角色无法访问的位置。
在穿越网格时,仅使用四个主要方向(上、下、左、右)我希望角色找到到达目的地的最短可行路径。例如,如果它从 [1,2] 开始并需要到达位置 [3,2],我希望它移动:向上 -> 向右 -> 向右 -> 向下。
以下是我目前用于确定可行解决方案的信息;有些地方不太对劲,但我想不出我的逻辑哪里出了问题:
DartPad Example用于交互功能代码。
import 'dart:collection';
class Point {
int x;
int y;
Point({required this.y,required this.x});
}
void main() {
print('Finding a viable solution for the shortest path...');
var grid = [
['','','','',''],
['','','','',''],
['','','','',''], // Character is at position grid[2][1]
['','','','',''], // Destination is position grid[2][3]
['','','','',''],
];
var characterPosition = Point(y: 2, x: 1);
var characterDestination = Point(y: 2, x: 3);
PathFinder pathFinder = PathFinder(grid, characterPosition, characterDestination);
if (pathFinder.solutionExists) {
print('...Solution exists!');
for (Point point in pathFinder.solution) {
print('(${point.y},${point.x})');
}
}
else {
print('...No solution exists.');
}
}
class PathFinder {
late Queue<Point> solution;
late bool solutionExists;
PathFinder(grid, characterPosition, characterDestination) {
// Applying BFS on matrix cells.
Queue<Point> queue = Queue<Point>();
queue.add(new Point(y: characterPosition.y, x: characterPosition.x));
List<List<bool>> visited = List.generate(
grid.length,
(index) => List.generate(
grid[0].length,
(index) => false,
growable: false,
),
growable: false,
);
visited[characterPosition.y][characterPosition.x] =
true;
while (queue.isNotEmpty) {
Point point = queue.removeLast();
// Destination found
if (point.x == characterDestination.x &&
point.y == characterDestination.y) {
this.solutionExists = true;
this.solution = queue;
return;
}
// moving up
if (_isValid(x: point.x, y: point.y - 1, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y - 1, x: point.x));
visited[point.y - 1][point.x] = true;
}
// moving down
if (_isValid(x: point.x, y: point.y + 1, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y + 1, x: point.x));
visited[point.y + 1][point.x] = true;
}
// moving left
if (_isValid(x: point.x - 1, y: point.y, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y, x: point.x - 1));
visited[point.y][point.x - 1] = true;
}
// moving right
if (_isValid(x: point.x + 1, y: point.y, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y, x: point.x + 1));
visited[point.y][point.x + 1] = true;
}
}
this.solutionExists = false;
this.solution = queue;
return;
}
bool _isValid({required int x, required int y, required List<List<String>> grid, required List<List<bool>> visited}) {
if (x >= 0 &&
y >= 0 &&
x < grid[0].length &&
y < grid.length &&
grid[y][x] != '' &&
visited[y][x] == false) {
return true;
}
return false;
}
}
如果你运行这个(使用DartPad),你可以看到输出是:
Finding a viable solution for the shortest path...
...Solution exists!
(1,1)
(3,3)
(1,4)
此输出与我预期的不完全相同,这意味着我显然搞砸了。我无法弄清楚我到底应该怎么做才能正确实施这个寻路算法,所以任何见解、建议或帮助都将不胜感激!提前致谢!!
逻辑是“广度优先搜索”。 List cameFrom 将每个节点元素设置为它来自的节点元素。图片:
现在重建整个路径,从目的地到起始节点。
DartPad 上的 Dart 解决方案。
Dart 不是我的第一语言,所以请随意改变方法...
import 'dart:collection';
// *****************************************************************************
// ***** class Point
class Point {
int x;
int y;
Point({required this.y, required this.x});
}
// *****************************************************************************
// ***** class PathFinder
class PathFinder {
List<List<String>> grid;
int gridWidth = 0;
int gridHeight = 0;
late Queue<Point> solution;
late bool solutionExists;
// ---------------------------------------------------------------------------
// ----- constructor
PathFinder(this.grid, characterPosition, characterDestination) {
// integers for easier manipulation
Queue<int> frontier = Queue<int>();
List<int> cameFrom = List.generate(
this.grid[0].length * this.grid.length,
(int index) => -1,
growable: false,
);
this.gridWidth = this.grid[0].length;
this.gridHeight = this.grid.length;
frontier.add(this._convert2dto1d(characterPosition));
// +++++ Breadth First Search Logic begin
while (frontier.isNotEmpty) {
int current = frontier.removeFirst();
Queue<Point> neighbors = this._neighbors(_convert1dto2d(current));
for (Point node in neighbors) {
int node1d = this._convert2dto1d(node);
if (cameFrom[node1d] == -1) {
frontier.add(node1d);
cameFrom[node1d] = current;
}
}
}
// +++++ Breadth First Search Logic end
this.solutionExists = true;
// +++++ copy solution to 2d Queue<Point> begin
this.solution = Queue<Point>();
Point endNode = characterDestination;
this.solution.add(endNode);
while (
endNode.x != characterPosition.x || endNode.y != characterPosition.y) {
int endNode1d = this._convert2dto1d(endNode);
if (cameFrom[endNode1d] == -1) {
this.solutionExists = false;
break;
}
endNode = this._convert1dto2d(cameFrom[endNode1d]);
this.solution.addFirst(endNode);
}
// +++++ copy solution to 2d Queue<Point> end
return;
}
// ---------------------------------------------------------------------------
// ----- _convert2dto1d
// ----- Convert point to integer for easier manipulation
int _convert2dto1d(Point node) {
return node.y * this.gridWidth + node.x;
}
// ---------------------------------------------------------------------------
// ----- _convert1dto2d
// ----- Convert integer back to point
Point _convert1dto2d(int node1d) {
if (this.gridWidth == 0) {
return new Point(y: -1, x: -1);
}
int y = node1d ~/ this.gridWidth;
int x = node1d - y * this.gridWidth;
return new Point(y: y, x: x);
}
// ---------------------------------------------------------------------------
// ----- _neighbors
Queue<Point> _neighbors(Point node) {
Queue<Point> neighbors = Queue<Point>();
for (int dx = -1; dx <= 1; dx += 2) {
Point neighborNode = new Point(y: node.y, x: node.x + dx);
if (_isValidNode(neighborNode)) {
neighbors.add(neighborNode);
}
}
for (int dy = -1; dy <= 1; dy += 2) {
Point neighborNode = new Point(y: node.y + dy, x: node.x);
if (_isValidNode(neighborNode)) {
neighbors.add(neighborNode);
}
}
return neighbors;
}
// ---------------------------------------------------------------------------
// ----- _isValidNode
bool _isValidNode(Point node) {
if (node.x >= 0 &&
node.y >= 0 &&
node.x < this.gridWidth &&
node.y < this.gridHeight &&
this.grid[node.y][node.x] != '') {
return true;
}
return false;
}
}
// *****************************************************************************
// ***** main
void main() {
print('Finding a viable solution for the shortest path...');
var grid = [
['', '', '', '', ''],
['', '', '', '', ''],
['', '', '', '', ''], // Character is at position grid[2][1]
['', '', '', '', ''], // Destination is position grid[2][3]
['', '', '', '', ''],
];
var characterPosition = Point(y: 2, x: 1);
var characterDestination = Point(y: 2, x: 3);
PathFinder pathFinder =
PathFinder(grid, characterPosition, characterDestination);
if (pathFinder.solutionExists) {
print('...Solution exists!');
for (Point point in pathFinder.solution) {
print('(${point.y},${point.x})');
}
} else {
print('...No solution exists.');
}
}
我有一个二维数组,用于表示角色在游戏中的位置,我将其称为网格。网格是一个 5x5 大小的网格。并非网格上的所有 tiles/locations 都是角色可以穿越的可行位置。在示例图像中,您可以看到其中三个位置是水而不是陆地,表示角色无法访问的位置。
在穿越网格时,仅使用四个主要方向(上、下、左、右)我希望角色找到到达目的地的最短可行路径。例如,如果它从 [1,2] 开始并需要到达位置 [3,2],我希望它移动:向上 -> 向右 -> 向右 -> 向下。
以下是我目前用于确定可行解决方案的信息;有些地方不太对劲,但我想不出我的逻辑哪里出了问题:
DartPad Example用于交互功能代码。
import 'dart:collection';
class Point {
int x;
int y;
Point({required this.y,required this.x});
}
void main() {
print('Finding a viable solution for the shortest path...');
var grid = [
['','','','',''],
['','','','',''],
['','','','',''], // Character is at position grid[2][1]
['','','','',''], // Destination is position grid[2][3]
['','','','',''],
];
var characterPosition = Point(y: 2, x: 1);
var characterDestination = Point(y: 2, x: 3);
PathFinder pathFinder = PathFinder(grid, characterPosition, characterDestination);
if (pathFinder.solutionExists) {
print('...Solution exists!');
for (Point point in pathFinder.solution) {
print('(${point.y},${point.x})');
}
}
else {
print('...No solution exists.');
}
}
class PathFinder {
late Queue<Point> solution;
late bool solutionExists;
PathFinder(grid, characterPosition, characterDestination) {
// Applying BFS on matrix cells.
Queue<Point> queue = Queue<Point>();
queue.add(new Point(y: characterPosition.y, x: characterPosition.x));
List<List<bool>> visited = List.generate(
grid.length,
(index) => List.generate(
grid[0].length,
(index) => false,
growable: false,
),
growable: false,
);
visited[characterPosition.y][characterPosition.x] =
true;
while (queue.isNotEmpty) {
Point point = queue.removeLast();
// Destination found
if (point.x == characterDestination.x &&
point.y == characterDestination.y) {
this.solutionExists = true;
this.solution = queue;
return;
}
// moving up
if (_isValid(x: point.x, y: point.y - 1, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y - 1, x: point.x));
visited[point.y - 1][point.x] = true;
}
// moving down
if (_isValid(x: point.x, y: point.y + 1, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y + 1, x: point.x));
visited[point.y + 1][point.x] = true;
}
// moving left
if (_isValid(x: point.x - 1, y: point.y, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y, x: point.x - 1));
visited[point.y][point.x - 1] = true;
}
// moving right
if (_isValid(x: point.x + 1, y: point.y, grid: grid, visited: visited)) {
queue.add(new Point(y: point.y, x: point.x + 1));
visited[point.y][point.x + 1] = true;
}
}
this.solutionExists = false;
this.solution = queue;
return;
}
bool _isValid({required int x, required int y, required List<List<String>> grid, required List<List<bool>> visited}) {
if (x >= 0 &&
y >= 0 &&
x < grid[0].length &&
y < grid.length &&
grid[y][x] != '' &&
visited[y][x] == false) {
return true;
}
return false;
}
}
如果你运行这个(使用DartPad),你可以看到输出是:
Finding a viable solution for the shortest path...
...Solution exists!
(1,1)
(3,3)
(1,4)
此输出与我预期的不完全相同,这意味着我显然搞砸了。我无法弄清楚我到底应该怎么做才能正确实施这个寻路算法,所以任何见解、建议或帮助都将不胜感激!提前致谢!!
逻辑是“广度优先搜索”。 List cameFrom 将每个节点元素设置为它来自的节点元素。图片:
现在重建整个路径,从目的地到起始节点。
DartPad 上的 Dart 解决方案。
Dart 不是我的第一语言,所以请随意改变方法...
import 'dart:collection';
// *****************************************************************************
// ***** class Point
class Point {
int x;
int y;
Point({required this.y, required this.x});
}
// *****************************************************************************
// ***** class PathFinder
class PathFinder {
List<List<String>> grid;
int gridWidth = 0;
int gridHeight = 0;
late Queue<Point> solution;
late bool solutionExists;
// ---------------------------------------------------------------------------
// ----- constructor
PathFinder(this.grid, characterPosition, characterDestination) {
// integers for easier manipulation
Queue<int> frontier = Queue<int>();
List<int> cameFrom = List.generate(
this.grid[0].length * this.grid.length,
(int index) => -1,
growable: false,
);
this.gridWidth = this.grid[0].length;
this.gridHeight = this.grid.length;
frontier.add(this._convert2dto1d(characterPosition));
// +++++ Breadth First Search Logic begin
while (frontier.isNotEmpty) {
int current = frontier.removeFirst();
Queue<Point> neighbors = this._neighbors(_convert1dto2d(current));
for (Point node in neighbors) {
int node1d = this._convert2dto1d(node);
if (cameFrom[node1d] == -1) {
frontier.add(node1d);
cameFrom[node1d] = current;
}
}
}
// +++++ Breadth First Search Logic end
this.solutionExists = true;
// +++++ copy solution to 2d Queue<Point> begin
this.solution = Queue<Point>();
Point endNode = characterDestination;
this.solution.add(endNode);
while (
endNode.x != characterPosition.x || endNode.y != characterPosition.y) {
int endNode1d = this._convert2dto1d(endNode);
if (cameFrom[endNode1d] == -1) {
this.solutionExists = false;
break;
}
endNode = this._convert1dto2d(cameFrom[endNode1d]);
this.solution.addFirst(endNode);
}
// +++++ copy solution to 2d Queue<Point> end
return;
}
// ---------------------------------------------------------------------------
// ----- _convert2dto1d
// ----- Convert point to integer for easier manipulation
int _convert2dto1d(Point node) {
return node.y * this.gridWidth + node.x;
}
// ---------------------------------------------------------------------------
// ----- _convert1dto2d
// ----- Convert integer back to point
Point _convert1dto2d(int node1d) {
if (this.gridWidth == 0) {
return new Point(y: -1, x: -1);
}
int y = node1d ~/ this.gridWidth;
int x = node1d - y * this.gridWidth;
return new Point(y: y, x: x);
}
// ---------------------------------------------------------------------------
// ----- _neighbors
Queue<Point> _neighbors(Point node) {
Queue<Point> neighbors = Queue<Point>();
for (int dx = -1; dx <= 1; dx += 2) {
Point neighborNode = new Point(y: node.y, x: node.x + dx);
if (_isValidNode(neighborNode)) {
neighbors.add(neighborNode);
}
}
for (int dy = -1; dy <= 1; dy += 2) {
Point neighborNode = new Point(y: node.y + dy, x: node.x);
if (_isValidNode(neighborNode)) {
neighbors.add(neighborNode);
}
}
return neighbors;
}
// ---------------------------------------------------------------------------
// ----- _isValidNode
bool _isValidNode(Point node) {
if (node.x >= 0 &&
node.y >= 0 &&
node.x < this.gridWidth &&
node.y < this.gridHeight &&
this.grid[node.y][node.x] != '') {
return true;
}
return false;
}
}
// *****************************************************************************
// ***** main
void main() {
print('Finding a viable solution for the shortest path...');
var grid = [
['', '', '', '', ''],
['', '', '', '', ''],
['', '', '', '', ''], // Character is at position grid[2][1]
['', '', '', '', ''], // Destination is position grid[2][3]
['', '', '', '', ''],
];
var characterPosition = Point(y: 2, x: 1);
var characterDestination = Point(y: 2, x: 3);
PathFinder pathFinder =
PathFinder(grid, characterPosition, characterDestination);
if (pathFinder.solutionExists) {
print('...Solution exists!');
for (Point point in pathFinder.solution) {
print('(${point.y},${point.x})');
}
} else {
print('...No solution exists.');
}
}