Наступит время, и нужно будет реализовать алгоритм нахождения пути. Если покопаться - то можно найти различные решения: А-звездочка, волновой алгоритм, Дейскстри…
Выбор будет зависеть от прославленной задачи. Мне пришлось реализовать алгоритм самому ничего короткого и на нужном языке C# мне не подошло. Поэтому опишу здесь как суть алгоритма (Волновой алгоритм), так и основу кода (ничего лишнего).
Суть алгоритма.
Существует 2-е точки одна старт другая финиш. Эти 2-е точки находятся в лабиринте нужно найти путь от старта к финишу.
Представление данных.
За лабиринт сойдет матрица (двухмерный массив) int. Если значение ячейки = 1 то это стена, если = 0 то ячейка проходима. Объект может двигаться в 4-х направлениях: вверх, вниз, влево, вправо.
Основной цикл (теория).
Начинаем со старта. Заносим в соседние 4-е ячейки значение шага. На следующем инкременте цикла увеличиваем значение шага на 1. Находим значение шаг-1 и заполняем соседние ячейки значением шага. Заполнять соседние ячейки нужно осторожно, ячейка не должна быть пройдена ранее или не должна быть стеной (непроходимой). И так пока не достигнем финиша…
Если решения нет – то нужно в основном цикле учитывать, что количество шагов не должно превышать количество ячеек на поле. Попробуйте несколько раз нарисовать на листочке «волны».
Реализация.
Первым делом заполняем копию матрицы таким образом, чтобы -2 это значение стены, а -1 это значение не пройденной ячейки. Я решил идти от финиша. Значение финиша = 0 = значение шага. Далее как по теории перебираем все ячейки пока не находим те которые == шагу. Когда находим – ставим в соседние ячейки в соответствии с правилами значение шага (еще не пройдена и не стена). Выходим из основного цикла когда значение ячейки старта не равно -1 или когда нет решения (количество шагов больше количества ячеек). В конце выводим полученную матрицу. Я не просчитываю сам путь в данном примере, для этого просто пройдитесь от финиша к старту по меньшей стоимости шага пока не достигните старта.
Выбор будет зависеть от прославленной задачи. Мне пришлось реализовать алгоритм самому ничего короткого и на нужном языке C# мне не подошло. Поэтому опишу здесь как суть алгоритма (Волновой алгоритм), так и основу кода (ничего лишнего).
Суть алгоритма.
Существует 2-е точки одна старт другая финиш. Эти 2-е точки находятся в лабиринте нужно найти путь от старта к финишу.
Представление данных.
За лабиринт сойдет матрица (двухмерный массив) int. Если значение ячейки = 1 то это стена, если = 0 то ячейка проходима. Объект может двигаться в 4-х направлениях: вверх, вниз, влево, вправо.
Основной цикл (теория).
Начинаем со старта. Заносим в соседние 4-е ячейки значение шага. На следующем инкременте цикла увеличиваем значение шага на 1. Находим значение шаг-1 и заполняем соседние ячейки значением шага. Заполнять соседние ячейки нужно осторожно, ячейка не должна быть пройдена ранее или не должна быть стеной (непроходимой). И так пока не достигнем финиша…
Если решения нет – то нужно в основном цикле учитывать, что количество шагов не должно превышать количество ячеек на поле. Попробуйте несколько раз нарисовать на листочке «волны».
Реализация.
Первым делом заполняем копию матрицы таким образом, чтобы -2 это значение стены, а -1 это значение не пройденной ячейки. Я решил идти от финиша. Значение финиша = 0 = значение шага. Далее как по теории перебираем все ячейки пока не находим те которые == шагу. Когда находим – ставим в соседние ячейки в соответствии с правилами значение шага (еще не пройдена и не стена). Выходим из основного цикла когда значение ячейки старта не равно -1 или когда нет решения (количество шагов больше количества ячеек). В конце выводим полученную матрицу. Я не просчитываю сам путь в данном примере, для этого просто пройдитесь от финиша к старту по меньшей стоимости шага пока не достигните старта.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AStarInMatrix
{
class AStar
{
int[,] Map;
int MapWidht;
int MapHeight;
int[,] WayMap;
/// <summary>
/// Конструктор
/// </summary>
public void ReadMap()
{
MapWidht = 16;
MapHeight = 9;
Map = new int[,]{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
WayMap = new int[10, 10];
}
/// <summary>
/// Отображение карты
/// </summary>
public void DrawMap()
{
for (int y = 0; y < MapHeight; y++)
{
Console.WriteLine();
for (int x = 0; x < MapWidht; x++)
if (Map[y,x]==1)
Console.Write("+");
else
Console.Write(" ");
}
Console.ReadKey();
FindWave(1, 1, 3, 4);
}
/// <summary>
/// Поиск пути
/// </summary>
/// <param name="startX">Координата старта X</param>
/// <param name="startY">Координата старта Y</param>
/// <param name="targetX">Координата финиша X</param>
/// <param name="targetY">Координата финиша Y</param>
public void FindWave(int startX, int startY, int targetX, int targetY)
{
bool add=true;
int[,] cMap = new int[MapHeight,MapWidht];
int x, y,step=0;
for (y = 0; y < MapHeight; y++)
for (x = 0; x < MapWidht; x++)
{
if (Map[y, x] == 1)
cMap[y, x] = -2;//индикатор стены
else
cMap[y, x] = -1;//индикатор еще не ступали сюда
}
cMap[targetY,targetX]=0;//Начинаем с финиша
while (add==true)
{
add = false;
for (y = 0; y < MapWidht; y++)
for (x = 0; x < MapHeight; x++)
{
if (cMap[x, y] == step)
{
//Ставим значение шага+1 в соседние ячейки (если они проходимы)
if (y - 1 >= 0 && cMap[x - 1, y] != -2 && cMap[x - 1, y] == -1)
cMap[x - 1, y] = step + 1;
if (x - 1 >= 0 && cMap[x, y - 1] != -2 && cMap[x, y - 1] == -1)
cMap[x, y - 1] = step + 1;
if (y + 1 < MapWidht && cMap[x + 1, y] != -2 && cMap[x + 1, y] == -1)
cMap[x + 1, y] = step + 1;
if (x + 1 < MapHeight && cMap[x, y + 1] != -2 && cMap[x, y + 1] == -1)
cMap[x, y + 1] = step + 1;
}
}
step++;
add = true;
if (cMap[startY,startX] != -1)//решение найдено
add = false;
if (step > MapWidht * MapHeight)//решение не найдено
add = false;
}
//Отрисовываем карты
for (y = 0; y < MapHeight; y++)
{
Console.WriteLine();
for (x = 0; x < MapWidht; x++)
if (cMap[y, x] == -1)
Console.Write(" ");
else
if (cMap[y, x] == -2)
Console.Write("#");
else
if (y == startY && x == startX)
Console.Write("S");
else
if (y == targetY && x == targetX)
Console.Write("F");
else
if (cMap[y, x] > -1)
Console.Write("{0}", cMap[y, x]);
}
Console.ReadKey();
}
}
}


а на сколько производителен даный алгоритм по сравнеению с другими ?
ОтветитьУдалитьВолновой алгоритм — один из основных при автоматизированной трассировке (разводке) печатных плат. Также одно из характерных применений волнового алгоритма — поиск кратчайшего расстояния на карте, в стратегических играх.
ОтветитьУдалитьДля меня примечательно использовать этот алгоритм в двухмерном массиве, а А-звездочка или Дейкстри во взвешенном графе.
Очень познавательно и доступно написано. Но код содержит ошибки в условиях при проверке ячеек. И более серьезную ошибку - выполнение пока step не достигнет кол-ва всех ячеек, зачем делать так? Гораздо проще проверить отсутствие помеченных ячеек в текущем шаге, если не одна не была помечена - завершаем цикл. Пришлось переписать : ) Но все равно автору респект!
ОтветитьУдалитьПо какому алгоритму лучше рассчитать путь по меньшей стоимости шага?
ОтветитьУдалитьСпасибо за статью!Очень помогла!
ОтветитьУдалитьХочу поделиться своим проектом. Написано на C# c использованием ООП.
ОтветитьУдалитьКод отлажен. Запускается, ищет и дает визуальное представление работы алгоритма.
https://github.com/Cuprumbur/Lee-algorithm
Тоже хочу своим поделиться. Помогло в написании моей первой стратегии. https://github.com/Team-on/TownsNWarriors
ОтветитьУдалить