public virtual void Bind(Module module, Dictionary <string, BoardFluid> FluidVariableLocations) { BoundModule = module; //module.BindingOperation = this; //The fluid types of the module layout, is changedto fit with the operation. //Thus for example, when the module is removed when the operations have finished, //the remaining droplets will have the correct type, and can be used by operations requiring the output of that module. int currentDroplet = 0; foreach (var fluid in InputFluids) { BoardFluid fluidType = new BoardFluid(fluid.OriginalFluidName); for (int i = 0; i < fluid.GetAmountInDroplets(FluidVariableLocations); i++) { module.GetInputLayout().Droplets[currentDroplet].SetFluidType(fluidType); currentDroplet++; } } BoardFluid outputFluidType = new BoardFluid(OutputVariable); foreach (var droplet in module.GetOutputLayout().Droplets) { droplet.SetFluidType(outputFluidType); } }
private static void DiscardDroplets(BoardFluid oldFluidType) { //This is done by changing their internal names, //so they can never be used in any operation later on. BoardFluid overwrittingFluidType = new BoardFluid(WASTE_FLUIDNAME_STRING); List <IDropletSource> dropletSources = new List <IDropletSource>(oldFluidType.dropletSources); foreach (var dropletSource in dropletSources) { dropletSource.SetFluidType(overwrittingFluidType); } }
private (BoardFluid, int) RecordNewFluidType(string fluidName, int currentTime, FluidBlock operation) { //If there already are droplets associated with the fluid name //they must be overwritten or moved to a waste module currentTime = RemoveFluidVariable(fluidName, currentTime, operation); BoardFluid fluidType = new BoardFluid(fluidName); if (!FluidVariableLocations.ContainsKey(fluidName)) { NewVariablesCreatedInThisScope.Add(fluidName); } FluidVariableLocations[fluidName] = fluidType; return(fluidType, currentTime); }
private BoardFluid RecordCompletlyNewFluidType(String fluidName) { if (FluidVariableLocations.ContainsKey(fluidName)) { throw new InternalRuntimeException("Logic error: RecordCompletlyNewFluidType is only for fluid names that have never been used before."); } BoardFluid fluidType = new BoardFluid(fluidName); if (!FluidVariableLocations.ContainsKey(fluidName)) { NewVariablesCreatedInThisScope.Add(fluidName); } FluidVariableLocations[fluidName] = fluidType; return(fluidType); }
public void PlaceStaticModules(List <StaticDeclarationBlock> staticDeclarations) { foreach (var staticDeclaration in staticDeclarations) { if (staticDeclaration is DropletDeclaration dropletDeclaration) { throw new NotImplementedException(); BoardFluid fluidType = RecordCompletlyNewFluidType(dropletDeclaration); Droplet droplet = (Droplet)dropletDeclaration.getAssociatedModule(); bool couldBePlaced = board.FastTemplatePlace(droplet); if (!couldBePlaced) { throw new RuntimeException("The input module couldn't be placed. The module is: " + droplet.ToString()); } //It is not really static, and thus must does not need to be registered as such. } else if (staticDeclaration is InputDeclaration input) { BoardFluid fluidType = RecordCompletlyNewFluidType(input); InputModule inputModule = new InputModule(fluidType, (int)input.Amount); bool couldBePlaced = board.FastTemplatePlace(inputModule); if (!couldBePlaced) { throw new RuntimeException("The input module couldn't be placed. The module is: " + inputModule.ToString()); } input.BoundModule = inputModule; inputModule.RepositionLayout(); StaticModules.Add(staticDeclaration.ModuleName, inputModule); NameOfInputFluids.Add(fluidType.FluidName); } else { Module staticModule = getAndPlaceFirstPlaceableModule(staticDeclaration, board); StaticModules.Add(staticDeclaration.ModuleName, staticModule); } } if (SHOULD_DO_GARBAGE_COLLECTION) { WasteModule waste = new WasteModule(); bool couldBePlaced = board.FastTemplatePlace(waste); if (!couldBePlaced) { throw new RuntimeException("The waste module couldn't be placed. The module is: " + waste.ToString()); } waste.GetInputLayout().Reposition(waste.Shape.x, waste.Shape.y); StaticModules.Add(WASTE_MODULE_NAME, waste); } }
public static Route RouteSingleDropletToModule(FluidBlock operation, Board board, int currentTime, Droplet dropletInput) { BoardFluid InputFluidType = dropletInput.GetFluidType(); Route route = RouteSingleDropletToModule(operation.BoundModule, board, currentTime, dropletInput); //The route is added to the module's routes: List <Route> inputRoutes; operation.InputRoutes.TryGetValue(InputFluidType.FluidName, out inputRoutes); if (inputRoutes == null) { inputRoutes = new List <Route>(); operation.InputRoutes.Add(InputFluidType.FluidName, inputRoutes); } inputRoutes.Add(route); return(route); }
public static Route RouteSingleDropletToModule(Module module, Board board, int currentTime, Droplet dropletInput) { BoardFluid InputFluidType = dropletInput.GetFluidType(); if (InputFluidType.GetNumberOfDropletsAvailable() < 1) { throw new RuntimeException("There isn't enough droplets of type " + InputFluidType.FluidName + " avaiable, to satisfy the requirement of the module: " + module.ToString()); } //Routes a droplet of type InputFluid to the module. Route route = DetermineRouteToModule(haveReachedDropletOfTargetType(dropletInput), module, dropletInput, board, currentTime); //Will be included as part of a later step. if (route == null) { throw new InternalRuntimeException("No route found. This should not be possible."); } //The droplet has been "used up"/it is now inside a module, //so it needs to be removed from its original position: RemoveRoutedDropletFromBoard(board, route); return(route); }
private int DoGarbageCollection(int currentTime, FluidBlock operation, BoardFluid oldFluidType) { int numberOfDropletsToRoute = oldFluidType.GetNumberOfDropletsAvailable(); WasteModule waste = (WasteModule)StaticModules[WASTE_MODULE_NAME]; waste.GetInputLayout().Droplets[0].FakeSetFluidType(oldFluidType); Droplet dropletInput = waste.GetInputLayout().Droplets[0]; List <Route> wasteRoutes = new List <Route>(); for (int i = 0; i < numberOfDropletsToRoute; i++) { Route route = Router.RouteSingleDropletToModule(waste, board, currentTime, dropletInput); wasteRoutes.Add(route); //The route is scheduled sequentially, so the end time of the current route (+1) should be the start of the next. //This will give an overhead of +1 for the operation starting time, for each droplet routed: currentTime = route.getEndTime() + 1; } if (wasteRoutes.Count > 0) { operation.WasteRoutes.Add(oldFluidType.FluidName, wasteRoutes); } return(currentTime); }
private int ExtractAndReassignDroplets(int currentTime, FluidBlock nextOperation, int requiredDroplets, BoardFluid targetFluidType, BoardFluid inputFluid) { //First it is checked if there is there even any fluid that needs to be transfered: if (requiredDroplets == 0) { return(currentTime); } int originalStartTime = currentTime; //Fluid needs to be allocated to a variable. //If the origin of the fluid is an input, a given amount of droplets needs to moved unto the board, //but if origin is simply droplets placed on the board, a simple renaiming can be done instead. //It will prioritize taking droplets already on the board, instead of taking droplets out of the inputs. //Trying to take as many droplets as possible from those already placed on the board, //to minimize the number of droplets that must be taken from the input modules: List <Droplet> availableDroplets = inputFluid.dropletSources.Where(dropletSource => dropletSource is Droplet) .Select(dropletSource => dropletSource as Droplet) .ToList(); int numberOfDropletsToTransfer = Math.Min(availableDroplets.Count, requiredDroplets); for (int i = 0; i < numberOfDropletsToTransfer; i++) { availableDroplets[i].SetFluidType(targetFluidType); } int numberOfDropletsTransfered = numberOfDropletsToTransfer; if (numberOfDropletsTransfered != requiredDroplets) { //As there aren't enough droplets placed on the board, to satisfy the requirement, //some must be taken from the input modules. List <InputModule> inputModules = inputFluid.dropletSources.Where(dropletSource => dropletSource is InputModule) .Select(dropletSource => dropletSource as InputModule) .ToList(); List <Route> dropletRoutes = new List <Route>(); nextOperation.InputRoutes.Add(inputFluid.FluidName, dropletRoutes); foreach (var inputModule in inputModules) { while (inputModule.DropletCount > 0 && numberOfDropletsTransfered < requiredDroplets) { numberOfDropletsTransfered++; inputModule.DecrementDropletCount(); Droplet droplet = new Droplet(targetFluidType, NameOfInputFluids); droplet.SetFluidConcentrations(inputModule); bool couldPlace = board.FastTemplatePlace(droplet); if (!couldPlace) { throw new RuntimeException("Not enough space for the fluid transfer."); } Route route = Router.RouteDropletToNewPosition(inputModule, droplet, board, currentTime); currentTime = route.getEndTime() + 1; dropletRoutes.Add(route); } if (numberOfDropletsTransfered == requiredDroplets) { break; } } if (numberOfDropletsTransfered != requiredDroplets) { throw new RuntimeException("Not enough droplets available. Fluid name: " + inputFluid.FluidName); } } else { currentTime += 1; //Necessary for the recording of the board below. } rectanglesAtDifferentTimes.Add(currentTime, board.CopyAllRectangles()); currentTime += 2; return(currentTime); }
public static (Board board, List <(Rectangle, int)> rectangles, List <(Module, int)> modules) ArrayToRectangles(int[] array, int arrayWidth, string fluidName = "random") { Assert.AreEqual(0, array.Length % arrayWidth); Board board = new Board(arrayWidth, array.Length / arrayWidth); board.EmptyRectangles.Clear(); Dictionary <int, List <(int x, int y)> > rectangleData = new Dictionary <int, List <(int x, int y)> >(); array.Distinct().Where(x => x != 0).ForEach(x => rectangleData.Add(x, new List <(int, int)>())); for (int y = 0; y < array.Length / arrayWidth; y++) { for (int x = 0; x < arrayWidth; x++) { int value = array[y * arrayWidth + x]; if (value != 0) { rectangleData[value].Add((x, y)); } } } BoardFluid fluid = new BoardFluid(fluidName); List <(Rectangle rect, int id)> rectangles = new List <(Rectangle, int)>(rectangleData.Count); List <(Module rect, int id)> modules = new List <(Module, int)>(rectangleData.Count); foreach (var data in rectangleData.OrderBy(x => x.Key).Select(x => x)) { int minX = data.Value.Min(d => d.x); int minY = data.Value.Min(d => d.y); int maxX = data.Value.Max(d => d.x); int maxY = data.Value.Max(d => d.y); int x = minX; int y = minY; int width = maxX - minX + 1; int height = maxY - minY + 1; Rectangle newRectangle = new Rectangle(width, height, x, y); rectangles.Add((newRectangle, data.Key)); if (data.Key < 0) { Droplet module = new Droplet(fluid); module.Shape = newRectangle; newRectangle.isEmpty = false; board.PlacedModules.Add(module, module); modules.Add((module, data.Key)); board.UpdateGridAtGivenLocation(module, newRectangle); } else { board.EmptyRectangles.Add(newRectangle, newRectangle); } } //Make adjacencies between all the rectangles List <Rectangle> onlyRectangles = rectangles.Select(x => x.rect).ToList(); rectangles.ForEach(x => x.rect.Connect(onlyRectangles)); return(board, rectangles, modules); }