/// <summary> /// Attempts to route from the start states to the destination states. The given states are both lists, but only one state from each list will be selected for the final routing. /// </summary> /// <param name="item">How much to route.</param> /// <param name="space">The initialstate from which the routing starts.</param> /// <param name="startPositions">The list of starting states. Only one will be used.</param> /// <param name="destinations">The list of desired destination states. Only one will be reached.</param> /// <returns>The solution state found after routing</returns> public Searchspace Route(ItemAmount item, Searchspace space, IEnumerable <RoutingCoordinate> startPositions, IEnumerable <RoutingCoordinate> destinations) { if (startPositions == null) { throw new ArgumentNullException("startPositions"); } if (destinations == null) { throw new ArgumentNullException("destinations"); } AStar <SolidRouteState> star = new AStar <SolidRouteState>(); star.StateGenerator = (s) => s.NextStates(Grader.CostForBuilding, Belt, BeltGroundNormal, BeltGroundFast, BeltGroundExpress, Inserter, LongInserter, FastInserter, Splitter); star.EndStateValidator = ValidateEndState; foreach (var dest in destinations) { star.AddDestination(dest); } foreach (var position in startPositions) { switch (position.State) { case RoutingCoordinate.CoordinateType.Belt: var startBuilding = new Belt(item, Belt, position.Position, position.Rotation); var tmpSpace1 = space.AddRoute(startBuilding); var startState = new SolidRouteState(startBuilding, 0, position.Position, tmpSpace1, RoutingCoordinate.CoordinateType.Belt, Depth.None, position.Rotation); star.AddState(startState); break; case RoutingCoordinate.CoordinateType.PlacedItem: case RoutingCoordinate.CoordinateType.Inserter: var startPlacedBuilding = new PlacedItem(item, position.Position); var tmpSpace2 = space.AddRoute(startPlacedBuilding); var startPlacedState = new SolidRouteState(startPlacedBuilding, 0, position.Position, tmpSpace2, RoutingCoordinate.CoordinateType.PlacedItem); star.AddState(startPlacedState); break; case RoutingCoordinate.CoordinateType.Splitter: var offsets = new BuildingRotation[] { BuildingRotation.West, BuildingRotation.North, BuildingRotation.West, BuildingRotation.North, }; var offsetDir = offsets[(int)position.Rotation]; var startSplitter1 = new Splitter(item, Splitter, position.Position, position.Rotation); var startSplitter2 = new Splitter(item, Splitter, position.Position + offsetDir.ToVector(), position.Rotation); var space1 = space.AddRoute(startSplitter1); var space2 = space.AddRoute(startSplitter2); var state1 = new SolidRouteState(startSplitter1, 0, position.Position - offsetDir.ToVector(), space1, RoutingCoordinate.CoordinateType.Belt, Depth.None, position.Rotation); var state2 = new SolidRouteState(startSplitter2, 0, position.Position + offsetDir.ToVector(), space2, RoutingCoordinate.CoordinateType.Belt, Depth.None, position.Rotation); var before = space.CalculateCollisions(position.Position - position.Rotation.ToVector()).OfType <Belt>() .Where((b) => b.Item.Item == item.Item) .Where((b) => b.Rotation == position.Rotation); var after = space.CalculateCollisions(position.Position + position.Rotation.ToVector()).OfType <Belt>() .Where((b) => b.Item.Item == item.Item) .Where((b) => b.Rotation == position.Rotation); if (before.Any() && after.Any()) { star.AddState(state1); star.AddState(state2); } var startPlacedBuilding2 = new PlacedItem(item, position.Position); var tmpSpace3 = space.AddRoute(startPlacedBuilding2); var startPlacedState2 = new SolidRouteState(startPlacedBuilding2, 0, position.Position, tmpSpace3, RoutingCoordinate.CoordinateType.PlacedItem); star.AddState(startPlacedState2); break; } } while (!star.Step()) { } return(star.EndState.Space); }
private IEnumerable <SolidRouteState> GeneratePlacedStates(Func <Searchspace, IPhysicalBuilding, double> costFunction) { var placedBuilding = new PlacedItem(((FlowBuilding)_building).Item, _position); placedBuilding.Previous.Add(Building); yield return(new SolidRouteState(placedBuilding, _cost + costFunction(_space, placedBuilding), _position, _space.AddRoute(placedBuilding), RoutingCoordinate.CoordinateType.PlacedItem)); }
public IEnumerable <FluidRouteState> NextStates(Func <Searchspace, IPhysicalBuilding, double> costFunction, Building pipeToGround, Building pipe) { if (_depth == Depth.Fluid) { Vector2 nextPos = _position + _direction.ToVector(); if (_undergroundLength < 9) { // Continue var flow = new UndergroundFlow(FlowBuilding.Item, nextPos, Depth.Fluid, _direction); flow.Previous.Add(_building); yield return(new FluidRouteState(flow, _cost + costFunction(_space, flow), flow.Position, _space.AddRoute(flow), flow.FlowDepth, flow.Rotation, false, _undergroundLength + 1)); } // Surface var surface = new Pipe(FlowBuilding.Item, pipeToGround, nextPos, _direction.Invert()); surface.Previous.Add(_building); yield return(new FluidRouteState(surface, _cost + costFunction(_space, surface), surface.Position, _space.AddRoute(surface), Depth.None, _direction, true)); } else { if (HasJustSurfaced) { Vector2 nextPos = _position + _direction.ToVector(); // Continue var cont = new FlowBuilding(FlowBuilding.Item, pipe, nextPos, BuildingRotation.North); cont.Previous.Add(_building); yield return(new FluidRouteState(cont, _cost + costFunction(_space, cont), cont.Position, _space.AddRoute(cont))); // Dive var dive = new FlowBuilding(FlowBuilding.Item, pipeToGround, nextPos, _direction); dive.Previous.Add(_building); yield return(new FluidRouteState(dive, _cost + costFunction(_space, dive), dive.Position, _space.AddRoute(dive), Depth.Fluid, _direction)); } else { BuildingRotation[] rotations = new BuildingRotation[] { BuildingRotation.North, BuildingRotation.East, BuildingRotation.South, BuildingRotation.West }; foreach (var rotation in rotations) { Vector2 nextPos = _position + rotation.ToVector(); // Straight var cont = new FlowBuilding(FlowBuilding.Item, pipe, nextPos, BuildingRotation.North); cont.Previous.Add(_building); yield return(new FluidRouteState(cont, _cost + costFunction(_space, cont), cont.Position, _space.AddRoute(cont))); // Dive var dive = new FlowBuilding(FlowBuilding.Item, pipeToGround, nextPos, rotation); dive.Previous.Add(_building); yield return(new FluidRouteState(dive, _cost + costFunction(_space, dive), dive.Position, _space.AddRoute(dive), Depth.Fluid, rotation)); } } } }