using System.Collections.Generic;
public static void Main()
public static void day7()
var sampleInput = @"Step C must be finished before step A can begin.
Step C must be finished before step F can begin.
Step A must be finished before step B can begin.
Step A must be finished before step D can begin.
Step B must be finished before step E can begin.
Step D must be finished before step E can begin.
Step F must be finished before step E can begin.";
var split = new List<string>(sampleInput.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None));
var pairs = split.Select(l => (A: l.Between("Step ", " "), B: l.Between("before step ", " "))).ToArray();
var allSteps = pairs.Select(p => p.A).Concat(pairs.Select(p => p.B)).Distinct();
var pendingSteps = allSteps.OrderBy(s => s).ToList();
var stepAlist = pairs.Select(p => p.A).Distinct();
var stepBlist = pairs.Select(p => p.B).Distinct();
var completedSteps = new List<string>();
var firstStep = stepAlist.Where(s => !stepBlist.Contains(s)).OrderBy(s => s).FirstOrDefault();
var nextStep = firstStep;
IOrderedEnumerable<string> FindPreReqs(string step) =>
pairs.Where(pair => pair.B == step && !completedSteps.Contains(pair.A))
.Select(pair => pair.A).OrderBy(s => s);
void TryExecuteStep(string step)
if (completedSteps.Contains(step))
if (pendingSteps.Contains(step)) pendingSteps.Remove(step);
pendingSteps.Remove(step);
completedSteps.Add(step);
while (pendingSteps.Any())
foreach (var step in pendingSteps)
var preReqs = FindPreReqs(step);
TryExecuteStep(nextStep);
Console.WriteLine($"{String.Join("", completedSteps)}");
public static class Utilities
public static List<string> SplitLines(this string input) => new List<string>(input.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None));
public static string Between(this string @this, int startOffset = 0, string from = null, string until = null, StringComparison comparison = StringComparison.InvariantCulture)
var fromLength = (from ?? string.Empty).Length;
var startIndex = !string.IsNullOrEmpty(from)
? @this.IndexOf(from, comparison) + fromLength
startIndex += startOffset;
if (startIndex < fromLength) { throw new ArgumentException("from: Failed to find an instance of the first anchor"); }
var endIndex = !string.IsNullOrEmpty(until)
? @this.IndexOf(until, startIndex, comparison)
if (endIndex < 0) { throw new ArgumentException("until: Failed to find an instance of the last anchor"); }
var subString = @this.Substring(startIndex, endIndex - startIndex);
public static string Between(this string @this, string from = null, string until = null, StringComparison comparison = StringComparison.InvariantCulture)
return Between(@this, 0, from, until, comparison);