Esempio n. 1
0
        /// <summary>
        /// PathFinding main method
        /// </summary>
        /// <param name="startingCells"></param>
        /// <param name="exitCells"></param>
        /// <param name="selectFartherCells"></param>
        /// <param name="firstStepOnly"></param>
        /// <returns></returns>
        public bool FindPath(int StartingSubMapId, int[] ExitSubMapIds, bool FirstStepOnly = false)
        {
            Random rnd = new Random();

            ClearLogic();
            if (cells == null)
            {
                throw new Exception("Cells are not initialized");
            }
            if (StartingSubMapId < 0 || StartingSubMapId >= cells.Length)
            {
                return(false);                                                          // We need at least one starting cell
            }
            if (!FirstStepOnly && (ExitSubMapIds == null || ExitSubMapIds.Length == 0))
            {
                return(false);                                                                        // We need at least one exit cell for step 2
            }
            // PC starts at distance of 0. Set 0 to all possible starting cells
            cells[StartingSubMapId].distanceSteps = 0;

            //    cells[StartingCell].distanceSteps = 0;
            int NbMainLoop = 0;

            while (true)
            {
                NbMainLoop++;
                bool madeProgress = false;

                // Look at each square on the board.
                for (int CurrentSubMap = 0; CurrentSubMap < cells.Length; CurrentSubMap++)
                {
                    Int16[] LocalLinks = links[CurrentSubMap];
                    uint    penalty    = 0;

                    uint nexMapDistance = cells[CurrentSubMap].distanceSteps + 1;
                    foreach (Int16 Link in LocalLinks)
                    {
                        if (mapPenalties != null)
                        {
                            penalty = mapPenalties[Link];
                        }
                        if (cells[Link].distanceSteps > nexMapDistance + penalty)
                        {
                            cells[Link].distanceSteps = nexMapDistance + penalty;
                            madeProgress = true;
                        }
                    }
                }
                if (!madeProgress)
                {
                    break;
                }
            }

            if (FirstStepOnly)
            {
                return(true);
            }
            // Step 2
            // Mark the path from Exit to Starting position.
            // if several Exit cells, then get the lowest distance one = the closest from one starting cell
            // (or the highest distance one if selectFartherCells)
            ExitCell = ExitSubMapIds[0];
            uint MinDist = cells[ExitCell].distanceSteps;

            foreach (int cell in ExitSubMapIds)
            {
                if (cells[cell].distanceSteps < MinDist)
                {
                    ExitCell = cell;
                    MinDist  = cells[cell].distanceSteps;
                }
            }
            int CurrentCell = ExitCell;

            PathResult.Add(ExitCell);
            cells[ExitCell].isInPath = true;
            // Look through each MapNeighbour and find the square
            // with the lowest number of steps marked.
            int        lowestPoint;
            uint       lowest;
            List <int> LowestPoints = new List <int>(10);

            while (true)
            {
                // Look through each MapNeighbour and find the square
                // with the lowest number of steps marked.
                lowestPoint = CellInfo.CELL_ERROR;
                lowest      = DEFAULT_DISTANCE;

                foreach (int NewSubMapId in links[CurrentCell])
                {
                    uint count = cells[NewSubMapId].distanceSteps;
                    if (count < lowest)
                    {
                        LowestPoints.Clear();
                        lowest      = count;
                        lowestPoint = NewSubMapId;
                    }
                    else
                    if (count == lowest)     // If more than one point, then push it in the list, for random determination
                    {
                        if (LowestPoints.Count == 0)
                        {
                            LowestPoints.Add(lowestPoint);
                        }
                        LowestPoints.Add(NewSubMapId);
                    }
                }
                if (lowest == DEFAULT_DISTANCE)
                {
                    break;                  // Can't find a valid way :(
                }
                if (LowestPoints.Count > 1) // Several points with same distance =>> randomly select one of them
                {
                    lowestPoint = LowestPoints[rnd.Next(LowestPoints.Count)];
                }

                // Mark the subMap as part of the path if it is the lowest
                // number. Set the current position as the subMap with
                // that number of steps.
                PathResult.Add(lowestPoint);
                cells[lowestPoint].isInPath = true;
                CurrentCell = lowestPoint;

                if (cells[CurrentCell].distanceSteps == 0) // Exit reached
                {
                    StartingCell = CurrentCell;
                    // We went from closest Exit to a Starting position, so we're finished.
                    break;
                }
            }
            PathResult.Reverse(); // Reorder the path from starting position to target
            return(CurrentCell == StartingCell);
        }
Esempio n. 2
0
        /// <summary>
        /// PathFinding main method
        /// </summary>
        /// <param name="startingCells"></param>
        /// <param name="exitCells"></param>
        /// <param name="selectFartherCells"></param>
        /// <param name="firstStepOnly"></param>
        /// <returns></returns>
        public bool FindPath(short[] startingCells, short[] exitCells, bool selectFartherCells = false, bool firstStepOnly = false, int maxDistanceParam = CellInfo.DEFAULT_DISTANCE)
        {
            Random rnd = new Random();

            if ((startingCells == null) || (startingCells.Length == 0))
            {
                return(false);                                                        // We need at least one starting stCell
            }
            if (!firstStepOnly && (exitCells == null || exitCells.Length == 0))
            {
                return(false);                                                                // We need at least one exit stCell for step 2
            }
            // PC starts at distance of 0. Set 0 to all possible starting cells
            CellInfo[] changed    = new CellInfo[560];
            int        changedPtr = 0;

            CellInfo[] changing    = new CellInfo[560];
            int        changingPtr = 0;

            bool optimizerActiv = !firstStepOnly && !selectFartherCells; // This strong optimization may fail to find a path. In that case, the non-optimized algorithm is run

            while (true)
            {
                ClearLogic(startingCells, exitCells);
                uint EstimatedDistance = CellInfo.DEFAULT_DISTANCE;
                Cell bestStartingCell  = null;
                Cell bestEndingCell    = null;

                foreach (short stCell in startingCells)
                {
                    if (_cells[stCell] != null)
                    {
                        _cells[stCell].DistanceSteps = 0;
                        changed[changedPtr++]        = _cells[stCell];
                        if (!firstStepOnly && !selectFartherCells)
                        {
                            foreach (short exCell in exitCells)
                            {
                                if (exCell == stCell)
                                {
                                    PathResult = new List <short> {
                                        stCell
                                    };
                                    return(true); // Empty path : starting stCell = exit stCell
                                }
                                if (optimizerActiv)
                                {
                                    uint distance = _cells[stCell].Cell.ManhattanDistanceTo(_cells[exCell].Cell);
                                    if (distance < EstimatedDistance)
                                    {
                                        bestStartingCell  = _cells[stCell].Cell;
                                        bestEndingCell    = _cells[exCell].Cell;
                                        EstimatedDistance = distance;
                                    }
                                }
                            }
                        }
                    }
                }
                //    cells[StartingCell].distanceSteps = 0;
                int maxDistance = maxDistanceParam; // We won't search over this distance - this optimization is OK in all cases
                if (optimizerActiv && bestStartingCell == null || bestEndingCell == null)
                {
                    optimizerActiv = false;
                }

                while (changedPtr > 0)
                {
                    changingPtr = 0;
                    // Look at each square on the board.
                    while (changedPtr > 0)
                    {
                        CellInfo curCell = changed[--changedPtr];
                        if (curCell.IsCloseToEnemy && _isCautious)
                        {
                            continue; // Cautious mode (in or out of fight) : Can't move from a cell near an ennemy
                        }
                        if (curCell.DistanceSteps < maxDistance)
                        {
                            if (optimizerActiv) // Strong optimisation
                            {
                                uint lastEstimatedDistance = curCell.Cell.ManhattanDistanceTo(bestEndingCell);
                                uint startDistance         = curCell.Cell.ManhattanDistanceTo(bestStartingCell);
                                if (startDistance + lastEstimatedDistance > EstimatedDistance)
                                {
                                    continue;
                                }
                            }
                            //Debug.Assert((curCell != null && curCell.DistanceSteps < CellInfo.DEFAULT_DISTANCE));
                            short[] cellNeighbours = neighbours[curCell.CellId];
                            for (short i = 0; i < cellNeighbours.Length; i++)
                            {
                                CellInfo newCell = _cells[cellNeighbours[i]];
                                if (newCell == null)
                                {
                                    continue;
                                }
                                if (newCell.DistanceSteps != 0 && !SquareOpen(newCell, null))
                                {
                                    continue;
                                }
                                //uint currentDistance = newCell.Cell.ManhattanDistanceTo(_cells[exitCells[0]].Cell);
                                //if (currentDistance >= EstimatedDistance || currentDistance >= lastEstimatedDistance) continue;

                                int newPass = curCell.DistanceSteps;
                                if (curCell.IsCloseToEnemy)
                                {
                                    newPass++; // Penality when close of an ennemy (same in fight and RP map)
                                }
                                if (_isInFight)
                                {
                                    newPass++;
                                }
                                else
                                {
                                    newPass += newCell.Weight;
                                }

                                if (newCell.DistanceSteps > newPass)
                                {
                                    newCell.DistanceSteps   = newPass;
                                    changing[changingPtr++] = newCell;
                                    if (!firstStepOnly && !selectFartherCells && newPass < maxDistance && exitCells.Any(id => newCell.CellId == id))
                                    {
                                        maxDistance = newPass; // We won't search on distance over closest exit
                                    }
                                }
                            }
                            if (_isInFight)
                            {
                                continue;
                            }
                            cellNeighbours = diagNeighbours[curCell.CellId];
                            for (short i = 0; i < cellNeighbours.Length; i++) // Process diagonals
                            {
                                CellInfo newCell = _cells[cellNeighbours[i]];
                                if (newCell == null)
                                {
                                    continue;
                                }
                                if (newCell.DistanceSteps != 0 && !SquareOpen(newCell, null))
                                {
                                    continue;
                                }

                                int newPass = curCell.DistanceSteps;
                                if (curCell.IsCloseToEnemy)
                                {
                                    newPass++; // Penality when close of an ennemy (same in fight and RP map)
                                }
                                if (_isInFight)
                                {
                                    newPass++;
                                }
                                else
                                {
                                    newPass += (int)(newCell.Weight * 1.414);
                                }

                                if (newCell.DistanceSteps > newPass)
                                {
                                    newCell.DistanceSteps   = newPass;
                                    changing[changingPtr++] = newCell;
                                    if (!firstStepOnly && !selectFartherCells && newPass < maxDistance && exitCells.Any(id => newCell.CellId == id))
                                    {
                                        maxDistance = newPass;  // We won't search on distance over closest exit
                                    }
                                }
                            }
                        }
                    }
                    CellInfo[] tmpChanged = changed;
                    changed    = changing;
                    changedPtr = changingPtr;
                    changing   = tmpChanged;
                }
                if (firstStepOnly)
                {
                    return(true);
                }
                // Step 2
                // Mark the path from Exit to Starting position.
                // if several Exit cells, then get the lowest distance one = the closest from one starting cell
                // (or the highest distance one if selectFartherCells)
                ExitCell = exitCells[0];
                int MinDist = _cells[ExitCell].DistanceSteps;
                foreach (short cell in exitCells)
                {
                    if ((selectFartherCells && _cells[cell].DistanceSteps > MinDist) || (!selectFartherCells && _cells[cell].DistanceSteps < MinDist))
                    {
                        ExitCell = cell;
                        MinDist  = _cells[cell].DistanceSteps;
                    }
                }

                if (optimizerActiv == false || MinDist < CellInfo.DEFAULT_DISTANCE)
                {
                    break;                                                                 // No need to run a second unoptimized algorithm
                }
                else
                {
                    optimizerActiv = false;
                }
            }
            //int no = 0;
            //Debug.WriteLine("PathFinding from {0} ({1}) to {2} ({3})", _cells[startingCells[0]].cell, _cells[startingCells[0]].distanceSteps, _cells[ExitCell].cell, _cells[ExitCell].distanceSteps);

            /*List<Cell> ListMax = new List<Cell>();
             * List<Cell> ListInc = new List<Cell>();
             * foreach (var cell in _cells)
             * {
             *  if (cell.distanceSteps >= CellInfo.DEFAULT_DISTANCE)
             *      ListMax.Add(cell.cell);
             *  if (cell.distanceSteps <= MinDist)
             *      ListInc.Add(cell.cell);
             *  //else
             *  //    continue;
             *  Debug.Write(String.Format("{0} : {1}, ", cell.cell, cell.distanceSteps));
             *  if (no++ == 5)
             *  {
             *      Debug.WriteLine("");
             *      no = 0;
             *  }
             * }*/
            //Debug.WriteLine("");
            //BotManager.Instance.Bots[0].Character.ResetCellsHighlight();
            //BotManager.Instance.Bots[0].Character.HighlightCells(ListMax, Color.Black);
            //BotManager.Instance.Bots[0].Character.HighlightCells(ListMax, Color.DarkGray);
            short CurrentCell = ExitCell;

            PathResult.Add(ExitCell);
            _cells[ExitCell].IsInPath = true;
            CellInfo[] lowestPoints    = changed; // No ned to alloc a new one, this one won't be used anymore
            int        lowestPointsPtr = 0;
            short      lowestPoint;
            int        lowest;

            while (true)
            {
                // Look through each MapNeighbour and find the square
                // with the lowest number of steps marked.
                lowestPoint = CellInfo.CELL_ERROR;
                lowest      = CellInfo.DEFAULT_DISTANCE;
                short[] neighbours = GetNeighbours(CurrentCell, _isInFight);
                for (short i = 0; i < neighbours.Length; i++)
                {
                    //foreach (CellInfo newCell in ValidMoves(curCell, false))
                    CellInfo newCell = _cells[neighbours[i]];
                    if (newCell == null || (newCell.IsCloseToEnemy && _isCautious && newCell.DistanceSteps != 0))
                    {
                        continue;                                                                                           // In cautious mode, don't come close to an enemy
                    }
                    //for (CellInfo NewCell in ValidMoves(_cells[CurrentCell], true))
                    //{
                    int distance = newCell.DistanceSteps;

                    /*if (distance > CellInfo.DEFAULT_DISTANCE)
                     * {
                     *  Debug.Assert(false, "Distance shouldn't be higher than DEFAULT_DISTANCE", "Distance = {0} > Max = {1}", distance, CellInfo.DEFAULT_DISTANCE);
                     *  continue;
                     * }*/
                    if (distance < lowest)
                    {
                        lowestPointsPtr = 1;
                        lowest          = distance;
                        lowestPoints[0] = newCell;
                    }
                    else
                    if (distance == lowest)
                    {
                        lowestPoints[lowestPointsPtr++] = newCell;
                    }
                }
                if (lowest == CellInfo.DEFAULT_DISTANCE)
                {
                    break;               // Can't find a valid way :(
                }
                if (lowestPointsPtr > 1) // Several points with same distance =>> randomly select one of them
                {
                    lowestPoint = lowestPoints[rnd.Next(lowestPointsPtr)].CellId;
                }
                else
                {
                    lowestPoint = lowestPoints[0].CellId;
                }

                // Mark the square as part of the path if it is the lowest
                // number. Set the current position as the square with
                // that number of steps.
                PathResult.Add(lowestPoint);
                if (PathResult.Count > _cells.Length)
                {
                    Debug.Assert(false, "PathFinder can't find a path - overflow");
                    break;
                }
                //Debug.Assert(_cells[lowestPoint].IsInPath == false, "Point already in path", "CurrentCell : {0}, Lowest : {1} - distance : {2}, path : {3}", _cells[CurrentCell].Cell, _cells[lowestPoint].Cell, lowest, string.Join(",", _cells.Where(stCell => stCell.IsInPath)));
                _cells[lowestPoint].IsInPath = true;
                CurrentCell = lowestPoint;


                if (_cells[CurrentCell].DistanceSteps == 0) // Exit reached
                {
                    StartingCell = CurrentCell;
                    // We went from closest Exit to a Starting position, so we're finished.
                    break;
                }
            }
            PathResult.Reverse();
            return(CurrentCell == StartingCell);
        }