private List <JourneyStep> GetNextOptions(JourneyStep current, int caveDepth, int targetX, int targetY, HashSet <string> stepsCovered) { List <JourneyStep> options = new List <JourneyStep>(); int[] xMods = new[] { 0, 1, 0, -1 }; int[] yMods = new[] { -1, 0, 1, 0 }; for (int i = 0; i < 4; i++) { int x = current.X + xMods[i]; int y = current.Y + yMods[i]; if (x >= 0 && y >= 0) { int targetErosionLevel = CalculateErosionLevel(x, y, targetX, targetY, caveDepth); string targetSoilType = DetermineType(targetErosionLevel); List <int> targetEquipment = EquipmentAllowed(targetSoilType); if (targetEquipment.Contains(current.Equipment) && stepsCovered.Add($"{x},{y},{current.Equipment}")) { JourneyStep newStep = new JourneyStep() { X = x, Y = y, Time = current.Time + 1, Switching = 0, Equipment = current.Equipment, CurrentType = targetSoilType }; options.Add(newStep); } } // Add other allowed tool option foreach (int otherTool in EquipmentAllowed(current.CurrentType)) { if (otherTool != current.Equipment) { JourneyStep newStep = new JourneyStep() { X = current.X, Y = current.Y, Time = current.Time + 1, Switching = 6, Equipment = otherTool, CurrentType = current.CurrentType }; options.Add(newStep); } } } return(options); }
public int FindBestTimeThroughCave(int caveDepth, int targetX, int targetY) { int bestTime = int.MaxValue; // I struggled with this one because I wanted to use constructed strings instead of custom classes for the Hashset // but then I did not separate the values in the strings with commas, so it was mismatching the values that overlapped // This made me lose hours of work. HashSet <string> stepsCovered = new HashSet <string>(); Queue <JourneyStep> queue = new Queue <JourneyStep>(); JourneyStep start = new JourneyStep() { X = 0, Y = 0, Time = 0, Equipment = 2, CurrentType = ".", Switching = 0 }; queue.Enqueue(start); stepsCovered.Add("0,0,2"); do { JourneyStep currentStep = queue.Dequeue(); // Handle switching if (currentStep.Switching > 0) { if (currentStep.Switching != 1 || stepsCovered.Add($"{currentStep.X},{currentStep.Y},{currentStep.Equipment}")) { JourneyStep newStep = new JourneyStep() { X = currentStep.X, Y = currentStep.Y, Time = currentStep.Time + 1, Switching = currentStep.Switching - 1, Equipment = currentStep.Equipment, CurrentType = currentStep.CurrentType }; queue.Enqueue(newStep); } continue; } // If the currentStep time is > best time, then discard if (currentStep.Time > bestTime) { continue; } // We have reached the target if (currentStep.X == targetX && currentStep.Y == targetY) { int modTime = currentStep.Equipment == 2 ? currentStep.Time : currentStep.Time + 7; if (modTime < bestTime) { bestTime = modTime; } break; } // Add next options List <JourneyStep> options = GetNextOptions(currentStep, caveDepth, targetX, targetY, stepsCovered); foreach (JourneyStep option in options) { queue.Enqueue(option); } } while (queue.Count > 0); return(bestTime); }