private Result CalculateMap(Vertex v, Wrappy w, Status status)
        {
            List <Goal>    goals    = status.goals;
            List <PriGoal> priGoals = new List <PriGoal>();
            Map <int>      distMap  = new Map <int>(map.W, map.H, UNREACHABLE);

            distMap[w.Loc] = 0;
            //int min = int.MaxValue;
            var crossingEdges = new MinHeap <int, int>(N);
            var minVertices   = new bool[N];

            minVertices[v.Id] = true;
            int max_goals = Math.Min(map.H, goals.Count);

            foreach (var outgoingEdge in v.OutgoingEdges)
            {
                // Use a Heapify operation!
                crossingEdges.Insert(outgoingEdge.V2, outgoingEdge.Length);
            }

            while (crossingEdges.Count > 0)
            {
                //DijkstraPrettyPrinter.printDijkstraMap(distMap, w);
                var minEdge = crossingEdges.ExtractMin();

                int v2 = minEdge.Key;
                var newVertex = vertices[v2];
                int X = v2 % map.W, Y = v2 / map.W;
                distMap[X, Y] = minEdge.Value;
                if (minEdge.Value != 0)
                {
                    // cerca il GoTo di coordinate X, Y (cioè il più vicino, appena estratto dal minheap)
                    int i;
                    if ((i = goals.FindIndex((g) =>
                    {
                        if (g.IsGoTo)
                        {
                            Goal.GoTo goTo = (Goal.GoTo)g;
                            int x = goTo.Item1, y = goTo.Item2;
                            return(x == X && y == Y);
                        }
                        else
                        {
                            return(false);
                        }
                    })) >= 0)
                    {
                        Goal.GoTo goTo = (Goal.GoTo)goals[i];
                        int       x = goTo.Item1, y = goTo.Item2;

                        double pri = minEdge.Value;

                        if (w.remainingFastWheel > 0)
                        {
                            if (Math.Abs(w.Loc.x - x) % 2 == 1 ||
                                Math.Abs(w.Loc.y - y) % 2 == 1)
                            {
                                pri *= SKIP_PRI;
                            }
                            else
                            {
                                pri *= GOTO_PRI;
                            }
                        }

                        else
                        {
                            if (status.boosters.Exists((kvp) =>
                                                       kvp.Value.x == x &&
                                                       kvp.Value.y == y &&
                                                       kvp.Key == Booster.CloningPlatform))
                            {
                                if (status.collectedBoosters.Contains(Booster.Cloning) ||
                                    status.map[x, y] == Tile.Empty)
                                {
                                    pri *= GOTO_PRI;
                                }
                                else
                                {
                                    pri *= SKIP_PRI;
                                }
                            }

                            if (status.boosters.Exists((kvp) =>
                                                       kvp.Value.x == x &&
                                                       kvp.Value.y == y &&
                                                       kvp.Key == Booster.Manipulator))
                            {
                                pri *= GOTO_PRI;
                            }
                        }

                        priGoals.Add(new PriGoal {
                            goal = goTo, pri = pri
                        });
                        //if (priGoals.Count >= max_goals) goto quit;
                        //return new Result { distMap = distMap, priGoals = priGoals };
                    }
                }

                minVertices[v2] = true;
                //if (minEdge.Value < min)
                //    min = minEdge.Value;

                foreach (var newEdge in newVertex.OutgoingEdges)
                {
                    if (minVertices[newEdge.V2] || newEdge.Length == UNREACHABLE)
                    {
                        continue;
                    }

                    var edgeLength = newEdge.Length + minEdge.Value;

                    var edge = crossingEdges.Find(newEdge.V2);
                    if (edge != null)
                    {
                        if (edgeLength < edge.Value)
                        {
                            crossingEdges.Update(newEdge.V2, edgeLength);
                        }
                    }
                    else
                    {
                        crossingEdges.Insert(newEdge.V2, edgeLength);
                    }
                }
            }
quit:
            return(new Result {
                distMap = distMap, priGoals = priGoals
            });
        }
        public Result CalculateMap(Wrappy w, Status status)
        {
            Point p = w.Loc;

            return(CalculateMap(vertices[idAt(p.x, p.y)], w, status));
        }