private FactoryState Clone() { FactoryState newState = new FactoryState(); newState.cost = cost; newState.buildingSources.AddRange(buildingSources); newState.beltSources.AddRange(beltSources); newState.buildingConsumers.AddRange(buildingConsumers); return(newState); }
public static FactoryState MakeBasicText(int size) { FactoryState startState = new FactoryState(); for (int i = 0; i < size; i++) { startState.buildingSources.Add(new FactoryState.BuildingSource(i * 3, 0, 1)); startState.buildingSources.Add(new FactoryState.BuildingSource(i * 3, 6, 2)); } startState.buildingConsumers.Add(new FactoryState.BuildingConsumer(size * 3, 3, 1, 2)); Console.WriteLine(5 * size - 2); // expectedCost return(startState); }
public static int Solve(FactoryState startState) { HashSet <FactoryState> explored = new HashSet <FactoryState>(); SortedList <int, List <FactoryState> > priorityQueue = new SortedList <int, List <FactoryState> >(); priorityQueue.Add(startState.cost + startState.Heuristic(), new List <FactoryState>() { startState }); while (true) { var headList = priorityQueue.First().Value; var head = headList.Last(); headList.RemoveAt(headList.Count - 1); if (explored.Contains(head)) { continue; } explored.Add(head); if (priorityQueue.First().Value.Count == 0) { priorityQueue.RemoveAt(0); } if (head.Heuristic() == 0) { int totalCount = priorityQueue.Sum(x => x.Value.Count); return(head.cost); } foreach (var nextState in head.NextStates()) { if (explored.Contains(nextState)) { continue; } int newCost = nextState.cost + nextState.Heuristic(); if (!priorityQueue.ContainsKey(newCost)) { priorityQueue.Add(newCost, new List <FactoryState>()); } if (newCost > 13) { continue; } priorityQueue[newCost].Add(nextState); } } throw new NotImplementedException(); }
public override bool Equals(object obj) { FactoryState that = obj as FactoryState; if (cost != that.cost) { return(false); } if (buildingSources.Count != that.buildingSources.Count) { return(false); } if (beltSources.Count != that.beltSources.Count) { return(false); } if (buildingConsumers.Count != that.buildingConsumers.Count) { return(false); } for (int i = 0; i < buildingSources.Count; i++) { if (buildingSources[i].x != that.buildingSources[i].x) { return(false); } if (buildingSources[i].y != that.buildingSources[i].y) { return(false); } if (buildingSources[i].itemType != that.buildingSources[i].itemType) { return(false); } } for (int i = 0; i < beltSources.Count; i++) { if (beltSources[i].x != that.beltSources[i].x) { return(false); } if (beltSources[i].y != that.beltSources[i].y) { return(false); } if (beltSources[i].itemType1 != that.beltSources[i].itemType1) { return(false); } if (beltSources[i].itemType2 != that.beltSources[i].itemType2) { return(false); } if (beltSources[i].direction != that.beltSources[i].direction) { return(false); } } for (int i = 0; i < buildingConsumers.Count; i++) { if (buildingConsumers[i].x != that.buildingConsumers[i].x) { return(false); } if (buildingConsumers[i].y != that.buildingConsumers[i].y) { return(false); } if (buildingConsumers[i].itemType1 != that.buildingConsumers[i].itemType1) { return(false); } if (buildingConsumers[i].itemType2 != that.buildingConsumers[i].itemType2) { return(false); } } return(true); }
internal IEnumerable <FactoryState> NextStates() { // extract from a building onto a belt for (int i = 0; i < buildingSources.Count; i++) { // 48 ways to export from a building onto a new belt for (int j = 0; j < 12; j++) { int newx = buildingSources[i].x + bxOffset[j]; int newy = buildingSources[i].y + byOffset[j]; int newx2 = buildingSources[i].x + bxOffset2[j]; int newy2 = buildingSources[i].y + byOffset2[j]; bool beltExistsAlready = beltSources.Any(x => x.x == newx && x.y == newy); if (beltExistsAlready) { int theBelt = beltSources.FindIndex(x => x.x == newx && x.y == newy); FactoryState nextState = this.Clone(); nextState.buildingSources.RemoveAt(i); bool isLeft = bIsLeft[j / 3 * 4 + beltSources[theBelt].direction]; int itemTypeInLane = isLeft ? beltSources[theBelt].itemType1 : beltSources[theBelt].itemType2; if (itemTypeInLane == 0 || itemTypeInLane == buildingSources[i].itemType) { BeltSource moddedBelt = beltSources[theBelt]; if (isLeft) { moddedBelt.itemType1 = buildingSources[i].itemType; } else { moddedBelt.itemType2 = buildingSources[i].itemType; } nextState.beltSources[theBelt] = moddedBelt; nextState.cost++; nextState.Finalize(); yield return(nextState); } } else { for (int k = 0; k < 4; k++) // direction of new belt { FactoryState nextState = this.Clone(); nextState.buildingSources.RemoveAt(i); bool isLeft = bIsLeft[j / 3 * 4 + k]; nextState.beltSources.Add(new BeltSource(newx, newy, isLeft ? buildingSources[i].itemType : 0, isLeft ? 0 : buildingSources[i].itemType, k)); nextState.cost += 2; nextState.Finalize(); yield return(nextState); } } } } //if (buildingSources.Count > 0) yield break; // force building export exploration first (can't do this yet) // progress a belt for (int i = 0; i < beltSources.Count; i++) { int newx = beltSources[i].x + xOffset[beltSources[i].direction]; int newy = beltSources[i].y + yOffset[beltSources[i].direction]; for (int j = 0; j < 4; j++) { if (new int[] { 1, 0, 3, 2 }[beltSources[i].direction] == j) { continue; // let's not go backwards } FactoryState nextState = this.Clone(); BeltSource moddedSource = nextState.beltSources[i]; moddedSource.x = newx; moddedSource.y = newy; moddedSource.direction = j; int colx = moddedSource.x + xOffset[moddedSource.direction]; int coly = moddedSource.y + yOffset[moddedSource.direction]; if (beltSources.Any(x => x.x == colx && x.y == coly && x.direction == j && x.itemType1 == moddedSource.itemType1 && x.itemType2 == moddedSource.itemType2)) { // the two belts combine nextState.beltSources.RemoveAt(i); nextState.cost++; nextState.Finalize(); yield return(nextState); } else { nextState.beltSources[i] = moddedSource; nextState.cost++; nextState.Finalize(); yield return(nextState); } } } // TODO: merge 2 belts // consume from belt // TODO: do occupied for this for (int i = 0; i < beltSources.Count; i++) { var nextState = this.Clone(); var belt = beltSources[i]; var moddedBelt = nextState.beltSources[i]; bool anyConsumer1 = buildingConsumers.Any(x => (x.itemType1 == belt.itemType1 || x.itemType2 == belt.itemType1) && Math.Abs(x.x - belt.x) == 3 && Math.Abs(x.y - belt.y) < 2); anyConsumer1 |= buildingConsumers.Any(x => (x.itemType1 == belt.itemType1 || x.itemType2 == belt.itemType1) && Math.Abs(x.y - belt.y) == 3 && Math.Abs(x.x - belt.x) < 2); bool anyConsumer2 = buildingConsumers.Any(x => (x.itemType1 == belt.itemType2 || x.itemType2 == belt.itemType2) && Math.Abs(x.x - belt.x) == 3 && Math.Abs(x.y - belt.y) < 2); anyConsumer2 |= buildingConsumers.Any(x => (x.itemType1 == belt.itemType2 || x.itemType2 == belt.itemType2) && Math.Abs(x.y - belt.y) == 3 && Math.Abs(x.x - belt.x) < 2); if (anyConsumer1) { moddedBelt.itemType1 = 0; } if (anyConsumer2) { moddedBelt.itemType2 = 0; } nextState.beltSources[i] = moddedBelt; if (moddedBelt.itemType1 == 0 && moddedBelt.itemType2 == 0) { nextState.beltSources.RemoveAt(i); } nextState.cost++; nextState.Finalize(); yield return(nextState); } // TODO: consume from building }