private IEnumerator BuildNewMaze() { float mazeFrameElementsBuilt = 0; mazeFrameMeshesArePresent = false; // Initialize maze creator MazeFrameCreator mazeFrameCreator = null; switch (mazeShape) { case 0: { mazeFrameCreator = new MazeFrameCreatorSquare3D(mazeSize, nQuadrants) { Scale = mazeScale, Jitter = mazeJitter }; break; } case 1: { mazeFrameCreator = new MazeFrameCreatorMeshIcosahedron(nDivisions, nQuadrants) { Scale = mazeScale, Jitter = mazeJitter }; break; } } // Set random seed selector System.Random randGen = new ConsistentRandom(); // Randomize order of difficulties int[] randomQuadrantIndices = Utilities.RandomIndices(nQuadrants); // Generate maze! if (nQuadrants != 0 && nQuadrants != difficulties.Length) { throw new System.ArgumentException("When using quadrants, nQuadrants and nDifficulties should be equal."); } List <MazeFrame> singleMazeFrames = new List <MazeFrame>(difficulties.Length); for (int iDifficulty = 0; iDifficulty < difficulties.Length; iDifficulty++) { List <MazeFrame> singleFrameSections = new List <MazeFrame>(nSections); for (int iSections = 0; iSections < nSections; iSections++) { // Create sections int quadrantInd; //if (nQuadrants != 0) { quadrantInd = iDifficulty; } if (nQuadrants != 0) { quadrantInd = randomQuadrantIndices[iDifficulty]; } else { quadrantInd = 0; } MazeFrame currSection = null; int currDifficulty = difficulties[iDifficulty]; int currSeedInd = randGen.Next(seedData[quadrantInd].seeds[currDifficulty].Length); mazeFrameCreator.RandomSeed = seedData[quadrantInd].seeds[currDifficulty][currSeedInd]; //mazeFrameCreator.RandomSeed = seedData[quadrantInd].seeds[iDifficulty][iSections]; if (nQuadrants == 0) { currSection = mazeFrameCreator.GenerateMaze(); } else { currSection = mazeFrameCreator.GenerateEmptyMazeFrame(); mazeFrameCreator.GenerateMaze(ref currSection, quadrantInd); currSection.SetOnShortestPath(currSection.Quadrants[quadrantInd], 0); // HACKY } //currSection.KeepOnlyShortestPathConnections(); //currSection.AddPathSegments(); // DEBUG if (nQuadrants != 0) { Debug.Log(currSection.GetNIntersectionsOnPath()[0] + " " + currSection.GetDifficulty(quadrantInd)[0] + " - " + seedData[quadrantInd].difficulties[currDifficulty][currSeedInd]); } else { Debug.Log(currSection.GetNIntersectionsOnPath()[0] + " " + currSection.GetDifficulty()[0]); } // DEBUG singleFrameSections.Add(currSection); mazeFrameElementsBuilt++; LevelBuiltProgressPercentage = (mazeFrameElementsBuilt / (difficulties.Length * nSections)) / 2; yield return(null); } MazeFrame currSingleFrame; if (singleFrameSections.Count > 1) { //MazeFrame currSingleFrame = MazeFrame.Concatenate(singleFrameSections, mazeFrameCreator.Scale, mazeDirection); currSingleFrame = MazeFrame.CombineShrink(singleFrameSections, shrinkFactor); } else { currSingleFrame = singleFrameSections[0]; } currSingleFrame.AddOffsetStartNode(Vector3.Scale(mazeDirection, mazeScale) * startOffsetFactor, true); currSingleFrame.AddOffsetEndNode(Vector3.Scale(mazeDirection, mazeScale) * endOffsetFactor, true); for (int iInc = 0; iInc < iDifficulty; iInc++) { currSingleFrame.IncrementShortestPathIndices(); } singleMazeFrames.Add(currSingleFrame); } if (singleMazeFrames.Count > 1) { mazeFrame = MazeFrame.Merge(singleMazeFrames); } else { mazeFrame = singleMazeFrames[0]; } //mazeFrame.ConnectUnconnectedNodes(); mazeFrame.AddPathSegments(); yield return(null); // Populate maze and get return splines and maze objects mazePopulator.PopulateWithSplineFittedBars(mazeFrame, ref mazeFrameSplines, ref mazeObjects, objectScaling); //mazePopulator.PopulateWithSplineFittedCylinders(mazeFrame, ref mazeFrameSplines, ref mazeObjects, objectScaling); // Wait till population is complete while (!mazeFrameMeshesArePresent) { if (mazePopulator.MazeObjectsPlaced == mazeFrameSplines.SplineSegments.Count) { mazeFrameMeshesArePresent = true; } yield return(null); } // Create and Initialize gravity frame gravityFrameController = new GravityFrameController(mazeFrame, mazeFrameSplines, gravJunctionDistFactor, gravPlaneWidth); yield return(null); // Place others PlacePlayerAndCamera(); PlaceEndPortal(); PlaceCubeOfDeath(); PlaceMindWarpTriggers(); }
/// <summary> /// /// Build connections inside maze frame using recursive backtracking algorithm. /// </summary> /// <param name="mazeFrame">Maze frame object.</param> protected void BuildMazeFrameUsingRecursiveBacktracking(ref MazeFrame mazeFrame) { if (mazeRandGen == null) { mazeRandGen = new ConsistentRandom(); } if (randGen == null) { randGen = new ConsistentRandom(); } // Build maze using recursive backtracking // From wikipedia: /* 1) Make the initial node the current node and mark it as visited * 2) While there are unvisited nodes * 1) If the current node has any neighbours which have not been visited * 1) Choose randomly one of the unvisited neighbours * 2) Push the current node to the stack * 3) Remove the wall between the current node and the chosen node * 4) Make the chosen node the current node and mark it as visited * 2) Else if stack is not empty * 1) Pop a node from the stack * 2) Make it the current node */ // Check start/end node active status if (!mazeFrame.StartNode.IsActive || !mazeFrame.EndNode.IsActive) { throw new System.Exception("Start/end nodes are required to be active."); } // Set storage of visit flags and create stack for visisted nodes int nNodesVisited = 0; Dictionary <string, bool> isVisited = new Dictionary <string, bool>(mazeFrame.Nodes.Count); foreach (MazeNode nd in mazeFrame.Nodes) { if (nd.IsActive) { isVisited.Add(nd.Identifier, false); } else { isVisited.Add(nd.Identifier, true); nNodesVisited++; } } Stack <MazeNode> nodeTrack = new Stack <MazeNode>(mazeFrame.Nodes.Count); // FIXME does preallocating help performance here? // Ignore nodes without neighbors foreach (MazeNode nd in mazeFrame.Nodes) { if (nd.AllNeighbors.Count == 0) { isVisited[nd.Identifier] = true; nNodesVisited++; } } //Initialize near startNode MazeNode currentNode = mazeFrame.StartNode; isVisited[currentNode.Identifier] = true; nNodesVisited++; while (nNodesVisited < mazeFrame.Nodes.Count) { // See if there are unvisited neighbors List <MazeNode> unvisitedNeighbors = new List <MazeNode>(); foreach (MazeNode nb in currentNode.AllNeighbors) { if (!isVisited[nb.Identifier]) { unvisitedNeighbors.Add(nb); } } if (unvisitedNeighbors.Count != 0) { // Add current node to stack (1) nodeTrack.Push(currentNode); // Select random neighbor (2) //MazeNode selNode = RandomlySelectNodeWithBiasTowardsForwards(currentNode, unvisitedNeighbors); //Node selNode = RandomlySelectNodeWithBiasTowardsNode(currentNode, unvisitedNeighbors, endNode.AllNeighbors[0], 2,mazeRandGen); MazeNode selNode = unvisitedNeighbors[mazeRandGen.Next(unvisitedNeighbors.Count)]; // Add as connected neighbor to current node object(3) and vice versa currentNode.AddConnectionByReference(selNode); // Switch to new node(4) and record visit currentNode = selNode; isVisited[currentNode.Identifier] = true; nNodesVisited++; } else if ((unvisitedNeighbors.Count == 0) && (nodeTrack.Count != 0)) { currentNode = nodeTrack.Pop(); } // Safety check if ((nodeTrack.Count == 0) && (nNodesVisited > mazeFrame.Nodes.Count)) { throw new System.Exception("Recursive backtracking loop did not terminate correctly."); } } // Sanity check foreach (MazeNode nb in mazeFrame.Nodes) { if (isVisited[nb.Identifier] == false) { throw new System.Exception("Recursive backtracking loop did not terminate correctly."); } } }
private IEnumerator CreateMazesFromSeeds() { // Parse difficulty float[,] difficultyBounds = new float[nDifficulties, 2]; float difficultyStartPad = difficultyLimits[0]; float difficultyEndPad = 1 - difficultyLimits[1]; float diffRange = 1 - (difficultyStartPad + difficultyEndPad); float currDiffSize = difficultySize * diffRange; float diffSpacing = (diffRange - (nDifficulties * currDiffSize)) / (nDifficulties - 1); if (diffSpacing < 0) { throw new System.Exception("Overlapping difficulties."); } for (int i = 0; i < (nDifficulties); i++) { difficultyBounds[i, 0] = difficultyStartPad + (currDiffSize + diffSpacing) * i; difficultyBounds[i, 1] = difficultyBounds[i, 0] + currDiffSize; } string boundsDisp = difficultyBounds[0, 0] + ">x<=" + difficultyBounds[0, 1]; for (int i = 1; i < nDifficulties; i++) { boundsDisp = boundsDisp + " | " + difficultyBounds[i, 0] + ">x<=" + difficultyBounds[i, 1]; } Debug.Log(boundsDisp); //seedList[0] = new List<int>(nMazes); // difficulty <=.20 //seedList[0] = new List<int>(nMazes); // difficulty >.20 <=.40 //seedList[0] = new List<int>(nMazes); // difficulty >.40 <=.60 //seedList[0] = new List<int>(nMazes); // difficulty >.60 <=80 //seedList[0] = new List<int>(nMazes); // difficulty >.80 <=1 // Set random seed int mainRandomSeed = System.Environment.TickCount; ConsistentRandom mainRandomGenenerator = new ConsistentRandom(mainRandomSeed); // Setup maze creators MazeFrameCreator mazeFrameCreator = null; switch (mazeShape) { case 0: { mazeFrameCreator = new MazeFrameCreatorSquare3D(mazeSize, nQuadrants); break; } case 1: { mazeFrameCreator = new MazeFrameCreatorMeshIcosahedron(divisions, nQuadrants); break; } } mazeFrameCreator.Scale = mazeScale; // Used in hunt and kill for determining when to hunt // Create level from new seeds int ittMax = 1; if (nQuadrants != 0) { ittMax = nQuadrants; } for (int iQuadrant = 0; iQuadrant < ittMax; iQuadrant++) { // Setup seed/difficulty list List <List <int> > seedList = new List <List <int> >(nDifficulties); for (int i = 0; i < nDifficulties; i++) { seedList.Add(new List <int>(nMazes)); } List <List <float> > difficultyList = new List <List <float> >(nDifficulties); for (int i = 0; i < nDifficulties; i++) { difficultyList.Add(new List <float>(nMazes)); } bool done = false; int count = 0; while (!done) { // set new seed int mazeSeed = mainRandomGenenerator.Next(); mazeFrameCreator.RandomSeed = mazeSeed; // get maze MazeFrame mazeFrame = mazeFrameCreator.GenerateEmptyMazeFrame(); if (nQuadrants != 0) { mazeFrame.SetActiveQuadrant(iQuadrant); } mazeFrameCreator.GenerateMaze(ref mazeFrame); // Save according to difficulty float difficulty; if (nQuadrants == 0) { difficulty = mazeFrame.GetDifficulty()[0]; } else { difficulty = mazeFrame.GetDifficulty(iQuadrant)[0]; } for (int i = 0; i < nDifficulties; i++) { if (difficulty > difficultyBounds[i, 0] && difficulty <= difficultyBounds[i, 1] && seedList[i].Count < nMazes) { seedList[i].Add(mazeSeed); difficultyList[i].Add(difficulty); } } // Check end condition done = true; for (int i = 0; i < nDifficulties; i++) { done = done && seedList[i].Count == nMazes; } // safety check count++; if (count == count * 100) { throw new System.Exception("Something went wrong."); } // Display progress string disp; if (nQuadrants == 0) { disp = count + ": " + seedList[0].Count; } else { disp = "quadrant" + (iQuadrant + 1) + "of" + nQuadrants + " | " + count + ": " + seedList[0].Count; } for (int i = 1; i < nDifficulties; i++) { disp = disp + ", " + seedList[i].Count; } Debug.Log(disp + " | d = " + difficulty.ToString("0.0000")); // Yield WaitForSecondsRealtime wait = null; if (wait == null) { wait = new WaitForSecondsRealtime(0.0001f); } if ((count % 10) == 0) { yield return(wait); } } // Convert to SeedData object if (nDifficulties == 5) { seedData = new SeedData(seedList[0].ToArray(), seedList[1].ToArray(), seedList[2].ToArray(), seedList[3].ToArray(), seedList[4].ToArray(), difficultyList[0].ToArray(), difficultyList[1].ToArray(), difficultyList[2].ToArray(), difficultyList[3].ToArray(), difficultyList[4].ToArray(), mazeSize, mazeFrameCreator.GetType().FullName); } else if (nDifficulties == 4) {// Convert to SeedData object seedData = new SeedData(seedList[0].ToArray(), seedList[1].ToArray(), seedList[2].ToArray(), seedList[3].ToArray(), difficultyList[0].ToArray(), difficultyList[1].ToArray(), difficultyList[2].ToArray(), difficultyList[3].ToArray(), mazeSize, mazeFrameCreator.GetType().FullName); } else if (nDifficulties == 3) {// Convert to SeedData object seedData = new SeedData(seedList[0].ToArray(), seedList[1].ToArray(), seedList[2].ToArray(), difficultyList[0].ToArray(), difficultyList[1].ToArray(), difficultyList[2].ToArray(), mazeSize, mazeFrameCreator.GetType().FullName); } else if (nDifficulties == 2) {// Convert to SeedData object seedData = new SeedData(seedList[0].ToArray(), seedList[1].ToArray(), difficultyList[0].ToArray(), difficultyList[1].ToArray(), mazeSize, mazeFrameCreator.GetType().FullName); } else { throw new System.Exception("Requested nDifficulty not implemented due to the stupid save part."); } // Save to disk string creatorName = ""; string filePath; switch (mazeShape) { case 0: { creatorName = mazeFrameCreator.GetType().FullName + "-" + mazeSize.ToString() + "-" + mazeScale.ToString(); break; } case 1: { creatorName = mazeFrameCreator.GetType().FullName + "-" + divisions.ToString() + "-" + mazeScale.ToString(); break; } } if (nQuadrants != 0) { filePath = filePathBase + "-" + creatorName + "-" + "quadrant" + (iQuadrant + 1) + "of" + nQuadrants + ".json"; } else { filePath = filePathBase + "-" + creatorName + ".json"; } SeedDataController.SaveSeedData(seedData, filePath); } Debug.Log("Done!"); Debug.Break(); #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #endif }