Алгоритм A-star для поиска пути шахматной фигуры

У меня проблема с моим алгоритмом A*. Для этого нужно найти кратчайшие пути на n*m доске. Мой алгоритм работает для короля и коня и выглядит следующим образом:

public List<Node> aStar(int[,] chessBoard , Tuple<int , int> startXY , Tuple<int , int> endXY , int piece)
{
  //Tuple<int[] , int[]> moves = getAllMoves(piece , chessBoard.GetLength(0) , chessBoard.GetLength(1));

  // This getAllMoves function on the previous row
  // returns all the possible moves in two arrays like so:

  int[] knightMovementY = { -2, -2, -1, -1, 1, 1, 2, 2 };
  int[] knightMovementX = { -1, 1, -2, 2, -2, 2, -1, 1 };
  var moves = new Tuple<int[],int[]>(knightMovementX, knightMovementY);

  List<Node> open = new List<Node>();
  List<Node> closed = new List<Node>();
  List<Node> zero = new List<Node>();
  Node currentNode = new Node(startXY);
  int newX = 0;
  int newY = 0;

  // Adding the first node to the open list
  open.Add(currentNode);

  // Checking the adjacent squares and adding them to the open list
  for (int i = 0 ; i < moves.Item1.Length ; i++)
  {
    newX = currentNode.Position.Item1 + moves.Item1[i];
    newY = currentNode.Position.Item2 + moves.Item2[i];
    if (newX >= 0 && newX < chessBoard.GetLength(0) && newY >= 0 && newY < chessBoard.GetLength(1))
    {
      if (chessBoard[newX , newY] == -1)
      {
        Tuple<int , int> newPos = new Tuple<int , int>(newX , newY);
        Node adjacentNode = new Node(newPos , currentNode , 1);
        open.Add(adjacentNode);
      }

    }
  }
  // Removing the start node from the open list and adding it to the closed list
  closed.Add(open[0]);
  open.RemoveAt(0);

  // Repeat until the open list is empty or exit with error
  while (open.Count != 0)
  {

    // Selecting the node with the lowest cost from the open list and adding it to the closed list 
    int lowest = 999;
    int lowestIndex = 0;
    for (int i = 0 ; i < open.Count() ; i++)
    {
      if (open[i].Cost < lowest)
      {
        lowest = open[i].Cost;
        lowestIndex = i;
      }
    }

    // If the target square is added to the closed list a path has been found
    closed.Add(open[lowestIndex]);
    if (open[lowestIndex].Position.Item1 == endXY.Item1 && open[lowestIndex].Position.Item2 == endXY.Item2)
    {
      return closed;
    }
    open.RemoveAt(lowestIndex);

    // Check all the adjacent squares that are not in a closed list, not blocked and fit on the game board.
    // Blocked squares have a value of -2 and open squares a value of -1
    currentNode = closed.ElementAt(closed.Count - 1);
    for (int i = 0 ; i < moves.Item1.Length ; i++)
    {
      bool isInClosed = false;
      bool isInOpened = false;
      newX = currentNode.Position.Item1 + moves.Item1[i];
      newY = currentNode.Position.Item2 + moves.Item2[i];
      if (newX >= 0 && newX < chessBoard.GetLength(0) && newY >= 0 && newY < chessBoard.GetLength(1))
      {

        if (chessBoard[newX , newY] == -1)
        {
          Tuple<int , int> newPos = new Tuple<int , int>(newX , newY);
          Node adjacentNode = new Node(newPos , currentNode , currentNode.Cost + 1);
          for (int j = 0 ; j < closed.Count ; j++)
          {
            if ((closed[j].Position.Item1 == adjacentNode.Position.Item1) && (closed[j].Position.Item2 == adjacentNode.Position.Item2))
            {
              isInClosed = true;
            }
          }
          // If a node is already in the open list and the cost of that node is larger
          // than the cost of the current node, change the parent of the node in the
          // open list to the current node
          if (isInClosed == false)
          {
            for (int x = 0 ; x < open.Count ; x++)
            {
              if ((open[x].Position.Item2 == adjacentNode.Position.Item1) && (open[x].Position.Item1 == adjacentNode.Position.Item2))
              {
                isInOpened = true;
                if (adjacentNode.Cost + 1 < open[x].Cost)
                {
                  open[x].Parent = adjacentNode;
                  open[x].Cost = adjacentNode.Cost + open[x].Cost;
                }
              }
            }
            // If a node is not in the open list, add it!
            if (isInOpened == false)
            {
              open.Add(adjacentNode);
            }
          }

        }
      }
    }
  }
  Console.WriteLine("No path found!");
  return zero;
}

Очень хотелось бы, чтобы она работала и на ладью, и на ферзя, и на слона. Проблема в том, что в тот момент, когда алгоритм встречает заблокированный узел со значением -2, то он пропускает его и проверяет следующий доступный ход.

Если я отмечу поля, на которые может ходить ладья, нулями, то

A  B  C  D  E  F G          A B C  D E F G
x -1 -1 -2 -1 -1 y  becomes x 0 0 -2 0 0 y 

По сути, я не знаю, что делать, когда встречается препятствие с шахматными фигурами, которые не могут их перепрыгнуть и могут перемещаться на много клеток за раз. Пропуск заблокированного квадрата не делает..

Спасибо всем заранее


person JoonasL    schedule 19.06.2012    source источник
comment
Разве вы не можете пометить все квадраты после заблокированного квадрата как заблокированные?   -  person usr    schedule 19.06.2012
comment
Заблокированные квадраты предоставляются во входном файле. Вы имеете в виду, что я должен заблокировать все квадраты справа от фактического заблокированного квадрата в алгоритме?   -  person JoonasL    schedule 19.06.2012
comment
Ну, я бы заблокировал все клетки, на которые фигура не может двигаться. A* работает на любом планарном графе, поэтому все, что вам нужно сделать, это правильно построить граф.   -  person usr    schedule 19.06.2012
comment
Но ладья может пойти, например, на Е1, если D1 заблокирована. Для этого достаточно сделать 3 хода (A1->A2->E2->E1). И даже если бы я заблокировал поля, это все равно позволило бы мне перейти от A1 к целевому полю G1, даже если между ними есть препятствия, потому что ладья может двигаться по горизонтали неограниченное количество ходов. Вот с этим у меня проблемы. Как-то изменить алгоритм, чтобы он не только запрещал шахматной фигуре наступать на заблокированную клетку, но и перешагивать через заблокированную клетку.   -  person JoonasL    schedule 19.06.2012
comment
Я понимаю, что вы говорите. Заблокированные и доступные поля зависят от положения ладьи в данный момент времени. A* способен справиться с этим. Постройте граф, в котором есть следующие ребра (среди прочих): A1->A2->E2->E1. Нужно только правильно построить график разрешенных перемещений.   -  person usr    schedule 19.06.2012
comment
Итак, на первом ходу я должен заблокировать каждую клетку, на которую не может пойти ладья, затем для новой позиции пересчитать граф и снова заблокировать все позиции, на которые не может пойти ладья?   -  person JoonasL    schedule 19.06.2012
comment
Нет, график статичен. Каждый квадрат является вершиной, и между всеми квадратами, между которыми может двигаться ваша фигура, существует ребро. Перемещение шахматных фигур полностью аналогично движению автомобилей по улицам. Перекресток = площадь, улица = край.   -  person usr    schedule 19.06.2012
comment
Блин, я хотел бы перенести это в чат, но у меня не хватает очков, чтобы говорить там. В общем, я настолько потерян, что это даже не смешно. Вы имеете в виду, что я должен переделать весь алгоритм? На данный момент у меня нет ребер, и граф одинаков для всех шахматных фигур. Прямо сейчас у меня есть двумерный список, в котором некоторые элементы являются заблокированными позициями, а некоторые — открытыми позициями. Нужно ли мне построить из него граф с ребрами между всеми вершинами, в которые я могу двигаться, а затем изменить свой алгоритм так, чтобы он проверял эти ребра, а не ходы, которые может сделать шахматная фигура, как я делаю сейчас?   -  person JoonasL    schedule 19.06.2012
comment
Вы получили это право. Я не думаю, что ты заблудился. То, что вам нужно, это просто стандартный поиск A *. См. stackoverflow.com/questions/ 2138642/ . Я думаю, что аналогия с автомобилем на дорогах действительно хороша, кстати. Именно для этого изначально создавался A*.   -  person usr    schedule 19.06.2012