GainType LKH::LKHAlg::Minimum1TreeCost(int Sparse) { Node *N, *N1 = 0; GainType Sum = 0; int Max = INT_MIN; MinimumSpanningTree(Sparse); N = FirstNode; do { N->V = -2; Sum += N->Pi; } while ((N = N->Suc) != FirstNode); Sum *= -2; while ((N = N->Suc) != FirstNode) { N->V++; N->Dad->V++; Sum += N->Cost; N->Next = 0; } FirstNode->Dad = FirstNode->Suc; FirstNode->Cost = FirstNode->Suc->Cost; do { if (N->V == -1) { Connect(N, Max, Sparse); if (N->NextCost > Max) { N1 = N; Max = N->NextCost; } } } while ((N = N->Suc) != FirstNode); N1->Next->V++; N1->V++; Sum += N1->NextCost; Norm = 0; do Norm += N->V * N->V; while ((N = N->Suc) != FirstNode); if (N1 == FirstNode) N1->Suc->Dad = 0; else { FirstNode->Dad = 0; Precede(N1, FirstNode); FirstNode = N1; } if (Norm == 0) { for (N = FirstNode->Dad; N; N1 = N, N = N->Dad) Follow(N, N1); for (N = FirstNode->Suc; N != FirstNode; N = N->Suc) N->Dad = N->Pred; FirstNode->Suc->Dad = 0; } return Sum; }
bool RoomAndCorridorMap::TryBuildMap(const Point& size, bool verbose) { size_ = size; tileset_.reset(new DefaultTileset()); Level level(size_); vector<Rect> rects; const int min_size = 6; const int max_size = 8; const int separation = 3; const int tries = size_.x*size_.y/(min_size*min_size); int tries_left = tries; while (tries_left > 0) { const Point size{RandInt(min_size, max_size), RandInt(min_size/2, max_size/2)}; const Rect rect{size, {RandInt(1, size_.x - size.x - 1), RandInt(1, size_.y - size.y - 1)}}; if (!level.PlaceRectangularRoom(rect, separation, &rects)) { tries_left -= 1; } } const int n = rects.size(); ASSERT(n > 0); MAYBE_DEBUG("Placed " << IntToString(n) << " rectangular rooms after " << IntToString(tries) << " attempts."); Array2d<double> graph = ConstructArray2d<double>(Point(n, n), 0); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { graph[i][j] = RectToRectDistance(rects[i], rects[j]); ASSERT((i == j) == (graph[i][j] == 0)); } } vector<Point> edges = MinimumSpanningTree(graph); MAYBE_DEBUG("Computed a minimal spanning tree with " << IntToString(edges.size()) << " edges."); int loop_edges = 0; Array2d<double> distances = ComputeTreeDistances(graph, edges); while (true) { Point best_edge; double best_ratio = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { double ratio = distances[i][j]/graph[i][j]; if (ratio > best_ratio) { best_edge = Point(i, j); best_ratio = ratio; } } } if (best_ratio < 2.0) { break; } edges.push_back(best_edge); double distance = graph[best_edge.x][best_edge.y]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { distances[i][j] = min(distances[i][j], min( distances[i][best_edge.x] + distance + distances[best_edge.y][j], distances[i][best_edge.y] + distance + distances[best_edge.x][j])); } } loop_edges += 1; } MAYBE_DEBUG("Added " << IntToString(loop_edges) << " high-ratio loop edges."); const double islandness = rand() % 3; for (int i = 0; i < 3; i++) { level.Erode(islandness); } level.ExtractFinalRooms(n, &rooms_); const double windiness = 1.0; for (const Point& edge : edges) { ASSERT(edge.x != edge.y); if (!level.DigCorridor(rooms_, edge.x, edge.y, windiness)) { MAYBE_DEBUG("Failed to dig corridor. Retrying..."); return false; } } MAYBE_DEBUG("Dug " << IntToString(edges.size()) << " corridors."); level.AddWalls(); starting_square_ = rooms_[0].GetRandomSquare(); MAYBE_DEBUG("Final map:" << level.ToDebugString()); PackTiles(level.tiles); return true; }