using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; namespace D20._1 { class Program { public class Group { public int Id { get; set; } public int Level { get; set; } public string Str { get; set; } public List Groups { get; set; } public SortedSet Possibilities { get; set; } public Group() { Groups = new List(); Possibilities = new SortedSet(new PC()); Str = ""; Id = 1; } } class PC : IComparer { public int Compare(string x, string y) => y.Length.CompareTo(x.Length); } static IEnumerable CombinePossibilities(string Str, List children, int depth = 0) { if (depth == children.Count) { yield return Str; yield break; } var child = children[depth]; foreach (var prevchildPossibility in child.Possibilities) foreach (var t in CombinePossibilities(Str.Replace(("(" + (char)child.Id + ")").ToString(), prevchildPossibility), children, depth + 1)) { if (Str.Contains(((char)child.Id).ToString()) == false) throw new Exception(); yield return t; } } static Group BuildGroups(int level, string priority, string regex, int index) { if (index >= regex.Length) return null; var group = new Group() { Level = level, Str = "" }; bool capture = true; while ( index < regex.Length && priority[index] >= level) { if (priority[index] > level && capture) { capture = false; var childGroup = BuildGroups(level + 1, priority, regex, index); if (childGroup != null) { childGroup.Id = group.Groups.Count + 1; group.Str += "(" + (char)childGroup.Id; group.Groups.Add(childGroup); } } else if (priority[index] == level) { capture = true; group.Str += regex[index]; } index++; } if (index < regex.Length) group.Str += regex[index]; return group; } static void Test(Group root) { IEnumerable possibilities; if (root.Groups.Count == 0) { var splittedPossibilities = root.Str.TrimStart('(').TrimEnd(')').Split("|"); foreach (var splittedPossibility in splittedPossibilities) root.Possibilities.Add(splittedPossibility); return; } foreach (var group in root.Groups) Test(group); possibilities = CombinePossibilities(root.Str, root.Groups); foreach (var possibility in possibilities) { var splittedPossibilities = possibility.TrimStart('(').TrimEnd(')').Split("|"); foreach (var splittedPossibility in splittedPossibilities) root.Possibilities.Add(splittedPossibility); } } static void Main(string[] args) { if (args.Length < 1) return; if (File.Exists(args[0]) == false) return; var file = File.OpenText(args[0]); var regex = file.ReadToEnd(); file.Close(); //regex = @"^ENNWSWW(NEWS|)SSSEEN(WNSE|)EE(SWEN|)NNN$"; //regex = @"^WSSEESWWWNW(S|NENNEEEENN(ESSSSW(NWSW|SSEN)|WSWWN(E|WWS(E|SS))))$"; //regex = @"^N(EEENWWW|N)$"; regex = regex.TrimStart('^').TrimEnd('$'); int par = 0, maxpar = 0; var priority = ""; for (var i = 0; i < regex.Length; ++i) { if (regex[i] == '(') { par++; if (par > maxpar) maxpar = par; } if (regex[i] == ')') par--; priority += (char)par; } var root = BuildGroups(0, priority, regex, 0); var sw = Stopwatch.StartNew(); Test(root); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); Dictionary<(int x, int y), int> positions = new Dictionary<(int x, int y), int>(); positions.Add((0, 0), 0); foreach (var path in root.Possibilities) { TestResult(path, positions); } int max = positions.Max(p => p.Value); int d = positions.Count(p => p.Value >= 1000); Console.WriteLine($"Ex 1 : {max}\nEx 2 ; {d}"); } private static void TestResult(string str, Dictionary<(int x, int y), int> positions) { int dist = 0; (int x, int y) pos = (0, 0); foreach (var c in str) { switch (c) { case 'N': pos.y -= 1; break; case 'S': pos.y += 1; break; case 'W': pos.x -= 1; break; case 'E': pos.x += 1; break; } if (positions.TryAdd(pos, dist + 1)) dist = dist + 1; else dist = Math.Min(dist + 1, positions[pos]); } } } }