/// <summary> /// Метод FindCell() возвращает /// направление по которому нужно пойти роботу, чтобы попасть в искомую соседнюю клетку. /// </summary> /// <param name="RequiredCell">Аргумент представляет искомую клетку /// </param> /// <returns>Возвращает направление по которому должен пойти робот, /// чтобы попасть в нужную соседнюю клетку и null, /// если по соседству такой клетки не найдено</returns> static Direction?FindCell(IRobot robot, Cell RequiredCell) { foreach (Direction neighbor in Enum.GetValues(typeof(Direction))) { Cell tmp = robot.AdjacentCell(neighbor); if (tmp == RequiredCell) { return(neighbor); } } return(null); }
static Direction?GetExitNeighbor(IRobot robot, List <Direction> UnvisitedNeighbors) { foreach (Direction neighbor in UnvisitedNeighbors) { Cell cell = robot.AdjacentCell(neighbor); if (cell.Type == CellType.Exit) { return(neighbor); } } return(null); }
/// <summary> /// Метод GetUnvisitedNeighbors() возвращает /// список направлений в которых находятся не посещенные клетки, которые не яляются стенами /// </summary> /// <param name="VisitedCells">Аргумент представляющий коллекцию посещенных клеток. /// Используется, чтобы проверить, что соседние клетки не были посещены ранее. /// </param> /// <param name="robot">Объект, реализующий интерфейс IRobot. /// Необходим для вызова метода AdjacentCell для просмотра соседних клеток по всем направлениям. /// </param> /// <returns>Возвращает список возможных направлений в виде списка объектов перечисления Direction</returns> static List <Direction> GetUnvisitedNeighbors(IRobot robot, List <Cell> VisitedCells) { List <Direction> UnvisitedNeighbors = new List <Direction>(); foreach (Direction neighbor in Enum.GetValues(typeof(Direction))) { Cell tmp = robot.AdjacentCell(neighbor); if (tmp.Type != CellType.Wall && !VisitedCells.Contains(tmp)) { UnvisitedNeighbors.Add(neighbor); } } return(UnvisitedNeighbors); }
// алгоритм поиска выхода роботом // он основан на алгоритме обхода графа в ширину с трекингом положений робота при помощи стека public static void FindExit(IRobot robot) { //если уже находимся в выходе то выходим if (robot.CurrentCell.Type == CellType.Exit) { return; } List <Cell> opened = new List <Cell>(); // открытые вершины - чьи соседи не просмотрены List <Cell> closed = new List <Cell>(); // закрыте вершины - чьи соседи просмотерны Stack <Tuple <Cell, Direction> > path = new Stack <Tuple <Cell, Direction> >(); // следим за роботом path.Push(new Tuple <Cell, Direction>(robot.CurrentCell, Direction.Left)); // для начальной вершины любое направление opened.Add(robot.CurrentCell); while (opened.Count > 0) { opened.Remove(robot.CurrentCell); closed.Add(robot.CurrentCell); bool move = false; Direction dir = Direction.Left; Cell cell2Move = null; // просмотрим все направления в порядке их объявления в перечислении Direction foreach (Direction d in Enum.GetValues(typeof(Direction))) { // получить ячейку var c = robot.AdjacentCell(d); // ячейка является стеной или cоседи ячейки просмотрены if (c.Type == CellType.Wall || closed.FirstOrDefault(item => item == c) != null) { continue; } // нашли выход if (c.Type == CellType.Exit) { // перемешаемся в ячейку robot.Move(d); move = true; // завершаем работу return; } // добавляем ячейку в список на рассмотрение opened.Add(c); // запоминаем куда двигать робота if (move == false) { dir = d; cell2Move = c; move = true; } } // двигаем робота if (move == true && cell2Move != null) { robot.Move(dir); path.Push(new Tuple <Cell, Direction>(cell2Move, dir)); } // если робот не был сдвинут, значит нужно вернуться в одну из оставшихся открытых вершин if (move == false && opened.Count > 0) { while (path.Count > 0) { var t = path.Pop(); // находим предыдущую ячейку и двигаемся к ней if (closed.FirstOrDefault(item => t.Item1 == item) == null) { throw new Exception("Открытая ячейка в пути!?"); } // двигаем робота в обратном направлении switch (t.Item2) { case Direction.Left: robot.Move(Direction.Right); break; case Direction.Right: robot.Move(Direction.Left); break; case Direction.Up: robot.Move(Direction.Down); break; case Direction.Down: robot.Move(Direction.Up); break; } Cell cur = robot.CurrentCell; // проверим есть ли открытые ячейки рядом foreach (Direction d in Enum.GetValues(typeof(Direction))) { var c = robot.AdjacentCell(d); if (opened.FirstOrDefault(item => item == c) != null) // переместимся в открытую ячейку { robot.Move(d); path.Push(new Tuple <Cell, Direction>(c, d)); break; } } if (cur != robot.CurrentCell) { break; // робот пришел в открытую ячейку } if (path.Count == 0) { throw new Exception("Путь не может быть пустым, если еще остались открытые вершины"); } } } } throw new ExitNotFoundException("Выход достичь нельзя!"); }