/// <summary> /// Creates a random payload of blocks constrained by the block manager. Payloads are by default /// created to be a size of 20 when randomly created /// </summary> /// <returns></returns> public static IndividualDatastructure createRandomPayload(int payloadsize) { ///So now that we've added our open space, we attempt to insert random blocks int count = 0; IndividualDatastructure payload = new IndividualDatastructure(); ///Here we need to init an open space. I want this to be at the centre of the 3D space int centre = IndividualManager.Instance.maxIndividualSize / 2; ///Calculating the offset of the centre double offset = BlockFunctions.calculateOffset(centre, centre, centre); payload.openSpaces.Add(offset); ///Here we grab the payload type that is tagged as such BlockType type = null; type = BlockManager.Instance.blockTypes[BlockFunctions.findBlockID("payload")]; if (type == null) { throw new Exception("There was no block of type payload defined"); } payloadsize = Math.Min(payloadsize, IndividualManager.Instance.startIndividualSize); ///While we have less blocks than desired, and less failed consecutive attempts than defined while (count < payloadsize && count < IndividualManager.Instance.startIndividualSize)///This number may need to be tweaked. I feel 200 consecutive failed attempts is enough though { if (BlockFunctions.insertBlockTypeAtRandom(payload, type)) { count++; } } Debug.Log("Payload created with size of " + count); return(payload); }
private static void alterPieces(Individual indiv) { ///For each pass defined by degree of mutation for (int i = 0; i < MutationManager.Instance.degreeToMutate; i++) { List <double> toDelete = new List <double>(); Dictionary <double, Block> replaceAtWith = new Dictionary <double, Block>(); ///for each block foreach (double b in indiv.hull.container.contents.Keys) { double rand = Randomizer.random.NextDouble(); ///WE DO NOT ALTER THE PAYLOAD NOR IGNORED BLOCKS if (indiv.payload.container.contents.Keys.Contains(b)) { continue; } if (rand < MutationManager.Instance.doNothingProbability) { continue; } rand = Randomizer.random.NextDouble(); ///If we should alter it if (Randomizer.random.NextDouble() < MutationManager.Instance.alterOrDeleteProbability) { ///RANDOMIZE BLOCK Block newBlock = BlockFunctions.generateRandomBlock(); replaceAtWith.Add(b, newBlock); } ///or delete it else { toDelete.Add(b); } } foreach (double b in toDelete) { indiv.hull.container.openSpaces.Add(b); indiv.hull.container.contents.Remove(b); } foreach (double b in replaceAtWith.Keys) { indiv.payload.container.contents[b] = replaceAtWith[b]; } } }
/// <summary> /// Creates a random payload of blocks constrained by the block manager. Payloads are by default /// created to be a size of 20 when randomly created /// </summary> /// <returns></returns> public static IndividualDatastructure createRandomHull(IndividualDatastructure hull, int hullSize) { int count = 0; ///Here i'm making sure that we don't fall into an infinite loop of trying to place blocks when it's not possible ///Normally this wouldn't be an issue, but because users can input their own blocks ///I need to safeguard against assholes. hullSize = Math.Min(hullSize, IndividualManager.Instance.startIndividualSize); ///While we have less blocks than desired, and less failed consecutive attempts than defined while (count < hullSize && count < IndividualManager.Instance.startIndividualSize)///This number may need to be tweaked. I feel 200 consecutive failed attempts is enough though { if (BlockFunctions.insertBlockAtRandom(hull)) { count++; } } return(hull); }
/// <summary> /// Pass in the structure which holds your blocks, as well as the type of block you would like added, and /// this will add that block at a random spot to your structure /// </summary> /// <param name="structure"></param> /// <param name="type"></param> /// <returns>The altered datastructure, null if failed</returns> internal static bool insertBlockTypeAtRandom(IndividualDatastructure structure, BlockType type) { double openSpace = BlockFunctions.randomOpenSpace(structure.openSpaces); ///This is our block facing face = Randomizer.RandomEnumValue <facing>(); rotation rot = Randomizer.RandomEnumValue <rotation>(); Block pBlock = new Block(type.UID, face, rot); ///If we've gotten to this point, then we can successfully place ourself into the individual /* * IVE BEEN GETTING AN ERROR WHERE WE TRY TO PLACE BLOCKS THAT ALREADY EXIST. * NO IDEA WHY THIS HAPPENS AND IT SHOULDN'T SO I'M SIMPLY PUTTING THIS CONDITIONAL HERE AS A JANK FIX */ if (structure.contents.ContainsKey(openSpace)) { return(false); } structure.contents.Add(openSpace, pBlock); ///Remove the open space from structure.openSpaces structure.openSpaces.Remove(openSpace); ///Add the possible neighbours of the placed block to our open neighbours list List <double> openConsiderations = BlockFunctions.addNeighboursToOpen(openSpace, structure.contents); ///Iterating over the open spots we are considering, and check to see if they are already filled or not. ///Then adding them to our open spaces list if they are not. foreach (double possible in openConsiderations) { if (structure.contents.ContainsKey(possible)) { continue; } structure.openSpaces.Add(possible); } return(true); }
private static void addPieces(Individual indiv) { List <double> insert = new List <double>(); foreach (double b in indiv.hull.container.openSpaces) { ///We have already added enough blocks if (indiv.hull.container.contents.Count >= IndividualManager.Instance.maxIndividualSize) { continue; } if (Randomizer.random.NextDouble() < MutationManager.Instance.additionProbability) { insert.Add(b); } } ///Doing it this way because we cannot alter a structure while iterating through it foreach (double inserting in insert) { BlockFunctions.insertBlockAtRandom(indiv.hull.container); } }
/// <summary> /// Places the blocks within this assortment into 3D space /// Uses the optimized block creation for deciding whether or not to render a block/ give it a collider /// This will also alter the individual by locating the centre of gravity, /// creating a block there with a mass of all the un-rendered blocks, /// then jointing the centre of gravity with all the rendered blocks. /// This also semi-optimizes the addition of the thrusters to the thruster /// index in the individual by performing that within the loop we are already doing. /// It does the same with the fuel amount. /// </summary> /// <param name="indiv"></param> /// </summary> public static GameObject instantiate(Individual passedIN) { ///Temporary variables for instantiating the Block structure as a unity 3-D object BlockManager blockMan = BlockManager.Instance; List <BlockType> blockTypes = blockMan.blockTypes; int centre = IndividualManager.Instance.maxIndividualSize / 2; float centreWeight = 0; Vector3 COGPosition = Vector3.zero; int COGWeight = 0; Dictionary <double, Block> contents = passedIN.hull.container.contents; GameObject parent = new GameObject(); parent.transform.position = new Vector3(centre, centre, centre); ///Iterate through all our positions/weights to find the centre of gravity foreach (double index in contents.Keys) { int blockWeight = blockTypes[contents[index].type].weight; int blockType = contents[index].type; int blockCost = blockTypes[contents[index].type].weight; ///Adding our values to the individual values passedIN.weight += blockWeight; passedIN.cost += blockCost; if (blockType == BlockFunctions.findBlockID("fuel")) { passedIN.fuelVolume++; } ///Create the 3D block GameObject created = BlockFunctions.createBlock(index, contents); ///Calculate the centre of gravity location COGPosition += (created.transform.position * blockWeight); centreWeight += blockWeight; ///If creation was allowed, we; if (created.GetComponent <MeshRenderer>().enabled) { ///Additionally, I optimize setting the thruster index here because we are already iterating over each block anyway if (contents[index].type == BlockFunctions.findBlockID("thruster")) { passedIN.thrusterIndex.Add(created); } else { passedIN.exteriorIndex.Add(created); } created.transform.SetParent(parent.transform); } ///If we do not render physically; else { ///Increment the COGWeight COGWeight += blockTypes[contents[index].type].weight; ///And destroy the block for it UnityEngine.Object.Destroy(created); } } ///After doing the physics for each block ///make sure our weight is non-zero if (passedIN.weight <= 0) { passedIN.weight = 1; } ///This is our centre of gravity. Now I need to create a block there, and set it's weight; COGPosition = COGPosition / centreWeight; parent.transform.position = Vector3.zero; Rigidbody rigid = parent.AddComponent <Rigidbody>(); rigid.centerOfMass = COGPosition; rigid.mass = passedIN.weight; rigid.drag = 0; return(parent); }