public static void FindExplorePath2Opt(ExploreCell start_cell, List <ExploreCell> explore_cells, CellsDistancer distances, ref List <Vec3> path) { path.Clear(); if (start_cell == null) { return; } List <int> cells_id_in_start_cell_network = distances.GetConnectedTo(start_cell.GlobalId); List <ExploreCell> best_tour = explore_cells.FindAll(c => cells_id_in_start_cell_network.Contains(c.GlobalId)); best_tour.RemoveAll(c => c.Explored || c.Neighbours.Count == 0); if (start_cell.Explored) { best_tour.Insert(0, start_cell); } if (best_tour.Count == 1) { path.Add(best_tour[0].Position); return; } float best_dist = GetTravelDistance(best_tour, distances); if (best_tour.Count < 90) { // based on http://en.wikipedia.org/wiki/2-opt while (true) { bool better_found = false; for (int i = 1; i < best_tour.Count - 1; ++i) { for (int k = i + 1; k < best_tour.Count; ++k) { float new_dist = Swap2OptDistance(best_tour, distances, i, k); if (new_dist < best_dist) { Swap2Opt(ref best_tour, i, k); best_dist = new_dist; better_found = true; break; } } if (better_found) { break; } } if (!better_found) { break; } } } else // greedy { // based on http://on-demand.gputechconf.com/gtc/2014/presentations/S4534-high-speed-2-opt-tsp-solver.pdf while (true) { float min_change = 0; int min_i = -1; int min_j = -1; for (int i = 0; i < best_tour.Count - 2; ++i) { for (int j = i + 2; j < best_tour.Count - 1; ++j) { int city_a = best_tour[i].GlobalId; int city_b = best_tour[i + 1].GlobalId; int city_c = best_tour[j].GlobalId; int city_d = best_tour[j + 1].GlobalId; float change = (distances.GetDistance(city_a, city_c) + distances.GetDistance(city_b, city_d)) - (distances.GetDistance(city_a, city_b) + distances.GetDistance(city_c, city_d)); if (change < min_change) { min_change = change; min_i = i + 1; min_j = j; } } } if (min_change >= 0) { break; } // apply min_i/min_j move ExploreCell t = best_tour[min_i]; best_tour[min_i] = best_tour[min_j]; best_tour[min_j] = t; } } //Navmesh.Log("[FindExplorePath 2-Opt] Final solution distance: " + GetTravelDistance(tour, distances)); foreach (ExploreCell cell in best_tour) { path.Add(cell.Position); } if (start_cell.Explored) { path.RemoveAt(0); } }
public static void FindExplorePath(ExploreCell start_cell, List <ExploreCell> explore_cells, CellsDistancer distances, ref List <Vec3> path) { //based on http://www.theprojectspot.com/tutorial-post/simulated-annealing-algorithm-for-beginners/6 path.Clear(); if (start_cell == null) { return; } List <int> cells_id_in_start_cell_network = distances.GetConnectedTo(start_cell.GlobalId); List <ExploreCell> best_solution = explore_cells.FindAll(c => cells_id_in_start_cell_network.Contains(c.Id)); best_solution.RemoveAll(c => (c.Explored || c.Neighbours.Count == 0) && c.GlobalId != start_cell.GlobalId); best_solution.Remove(start_cell); best_solution.Insert(0, start_cell); if (best_solution.Count == 1) { path.Add(best_solution[0].Position); return; } float best_energy = GetTravelDistance(best_solution, distances); List <ExploreCell> current_solution = best_solution; float current_energy = best_energy; Random rng = new Random(); double temp = 10000; double alpha = 0.999; double epsilon = 0.0001; int temp_iterations = 2; // Loop until system has cooled while (temp > epsilon) { for (int iter = 0; iter < temp_iterations; ++iter) { // Create new neighbour tour List <ExploreCell> new_solution = new List <ExploreCell>(current_solution); // Get a random positions in the tour int tour_pos_1 = rng.Next(1, new_solution.Count); int tour_pos_2 = rng.Next(1, new_solution.Count); // Swap them ExploreCell t = new_solution[tour_pos_1]; new_solution[tour_pos_1] = new_solution[tour_pos_2]; new_solution[tour_pos_2] = t; // Get energy of solutions float new_energy = GetTravelDistance(new_solution, distances); // Decide if we should accept the neighbour if (AcceptanceProbability(current_energy, new_energy, temp) >= rng.NextDouble()) { current_solution = new_solution; current_energy = new_energy; } // Keep track of the best solution found if (current_energy < best_energy) { best_solution = current_solution; best_energy = current_energy; } } // Cool system temp *= alpha; } //Navmesh.Log("[FindExplorePath] Final solution distance: " + best_energy); foreach (ExploreCell cell in best_solution) { path.Add(cell.Position); } if (start_cell.Explored) { path.RemoveAt(0); } }