/** * Generate a new galaxy. * * @return \Illuminate\Http\RedirectResponse */ public function generate() { // Start with a clean slate. DB::table('stars')->delete(); DB::table('star_links')->delete(); // Create new stars. $starCount = 200; /** * @var Star[] $unvisitedStars * @var Star[] $visitedStars * @var Star[] $allStars */ $unvisitedStars = []; $visitedStars = []; $allStars = []; for ($i = 0; $i < $starCount; $i++) { $star = new Star(['name' => $this->generateName()]); $star->save(); $unvisitedStars[$star->getKey()] = true; $allStars[$star->getKey()] = $star; } // Create links between stars. $totalLinks = 0; $starId = array_rand($allStars); $visitedStars[$starId] = $allStars[$starId]; unset($unvisitedStars[$starId]); // Random walk to generate a uniform spanning tree. while (!empty($unvisitedStars)) { $star = $visitedStars[$starId]; $otherStarId = array_rand($allStars); $otherStar = $allStars[$otherStarId]; if (!isset($visitedStars[$otherStarId])) { $star->exits()->attach($otherStar); $otherStar->exits()->attach($star); $visitedStars[$otherStarId] = $allStars[$otherStarId]; unset($unvisitedStars[$otherStarId]); $totalLinks++; } $starId = $otherStarId; } // Add some extra links to create cycles. for ($i = 0; $i < $totalLinks / 10; $i++) { $star = $allStars[array_rand($allStars)]; $otherStar = $allStars[array_rand($allStars)]; if ($star != $otherStar) { $star->exits()->attach($otherStar); $otherStar->exits()->attach($star); $totalLinks++; } } return redirect()->back()->with('status', 'Generated ' . $starCount . ' stars and ' . $totalLinks . ' star links.'); }