1
0

Program.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text.RegularExpressions;
  7. namespace D20._1
  8. {
  9. class Program
  10. {
  11. public class Group
  12. {
  13. public int Id { get; set; }
  14. public int Level { get; set; }
  15. public string Str { get; set; }
  16. public List<Group> Groups { get; set; }
  17. public SortedSet<string> Possibilities { get; set; }
  18. public Group()
  19. {
  20. Groups = new List<Group>();
  21. Possibilities = new SortedSet<string>(new PC());
  22. Str = "";
  23. Id = 1;
  24. }
  25. }
  26. class PC : IComparer<string>
  27. {
  28. public int Compare(string x, string y) => y.Length.CompareTo(x.Length);
  29. }
  30. static IEnumerable<string> CombinePossibilities(string Str, List<Group> children, int depth = 0)
  31. {
  32. if (depth == children.Count) { yield return Str; yield break; }
  33. var child = children[depth];
  34. foreach (var prevchildPossibility in child.Possibilities)
  35. foreach (var t in CombinePossibilities(Str.Replace(("(" + (char)child.Id + ")").ToString(), prevchildPossibility), children, depth + 1))
  36. {
  37. if (Str.Contains(((char)child.Id).ToString()) == false) throw new Exception();
  38. yield return t;
  39. }
  40. }
  41. static Group BuildGroups(int level, string priority, string regex, int index)
  42. {
  43. if (index >= regex.Length) return null;
  44. var group = new Group() { Level = level, Str = "" };
  45. bool capture = true;
  46. while (
  47. index < regex.Length &&
  48. priority[index] >= level)
  49. {
  50. if (priority[index] > level && capture)
  51. {
  52. capture = false;
  53. var childGroup = BuildGroups(level + 1, priority, regex, index);
  54. if (childGroup != null)
  55. {
  56. childGroup.Id = group.Groups.Count + 1;
  57. group.Str += "(" + (char)childGroup.Id;
  58. group.Groups.Add(childGroup);
  59. }
  60. }
  61. else if (priority[index] == level)
  62. {
  63. capture = true;
  64. group.Str += regex[index];
  65. }
  66. index++;
  67. }
  68. if (index < regex.Length) group.Str += regex[index];
  69. return group;
  70. }
  71. static void Test(Group root)
  72. {
  73. IEnumerable<string> possibilities;
  74. if (root.Groups.Count == 0)
  75. {
  76. var splittedPossibilities = root.Str.TrimStart('(').TrimEnd(')').Split("|");
  77. foreach (var splittedPossibility in splittedPossibilities) root.Possibilities.Add(splittedPossibility);
  78. return;
  79. }
  80. foreach (var group in root.Groups) Test(group);
  81. possibilities = CombinePossibilities(root.Str, root.Groups);
  82. foreach (var possibility in possibilities)
  83. {
  84. var splittedPossibilities = possibility.TrimStart('(').TrimEnd(')').Split("|");
  85. foreach (var splittedPossibility in splittedPossibilities) root.Possibilities.Add(splittedPossibility);
  86. }
  87. }
  88. static void Main(string[] args)
  89. {
  90. if (args.Length < 1) return;
  91. if (File.Exists(args[0]) == false) return;
  92. var file = File.OpenText(args[0]);
  93. var regex = file.ReadToEnd();
  94. file.Close();
  95. //regex = @"^ENNWSWW(NEWS|)SSSEEN(WNSE|)EE(SWEN|)NNN$";
  96. regex = @"^WSSEESWWWNW(S|NENNEEEENN(ESSSSW(NWSW|SSEN)|WSWWN(E|WWS(E|SS))))$";
  97. //regex = @"^N(EEENWWW|N)$";
  98. regex = regex.TrimStart('^').TrimEnd('$');
  99. int par = 0, maxpar = 0;
  100. var priority = "";
  101. for (var i = 0; i < regex.Length; ++i)
  102. {
  103. if (regex[i] == '(')
  104. {
  105. par++;
  106. if (par > maxpar) maxpar = par;
  107. }
  108. if (regex[i] == ')') par--;
  109. priority += (char)par;
  110. }
  111. var root = BuildGroups(0, priority, regex, 0);
  112. var sw = Stopwatch.StartNew();
  113. Test(root);
  114. sw.Stop();
  115. Console.WriteLine(sw.ElapsedMilliseconds);
  116. int max = 0;
  117. foreach (var path in root.Possibilities)
  118. {
  119. var r = GetResult(path);
  120. if (r > max) max = r;
  121. }
  122. Console.WriteLine(max);
  123. }
  124. private static int GetResult(string str)
  125. {
  126. (int x, int y) pos = (0, 0);
  127. HashSet<((int x, int y) from, (int x, int y) to)> doors = new HashSet<((int x, int y) from, (int x, int y) to)>();
  128. foreach (var c in str)
  129. {
  130. var bpos = pos;
  131. switch (c)
  132. {
  133. case 'N': pos.y -= 1; break;
  134. case 'S': pos.y += 1; break;
  135. case 'W': pos.x -= 1; break;
  136. case 'E': pos.x += 1; break;
  137. }
  138. doors.Add((bpos, pos));
  139. doors.Add((pos, bpos));
  140. }
  141. return GetBreadthFirstSearch(doors, pos);
  142. }
  143. // https://en.wikipedia.org/wiki/Breadth-first_search
  144. private static int GetBreadthFirstSearch(HashSet<((int x, int y) from, (int x, int y) to)> doors, (int x, int y) togo)
  145. {
  146. var nodesToVisit = new Queue<(int x, int y)>();
  147. var visitedNodes = new HashSet<(int x, int y)>();
  148. var meta = new Dictionary<(int x, int y), (int x, int y)>()
  149. {
  150. { (0, 0), (0, 0) }
  151. };
  152. nodesToVisit.Enqueue((0, 0));
  153. while (nodesToVisit.Count > 0)
  154. {
  155. var node = nodesToVisit.Dequeue();
  156. // Found it!
  157. if (node == togo)
  158. {
  159. var count = GetActionList(togo, meta, node);
  160. return count;
  161. }
  162. foreach ((int mx, int my) mv in new []{ (0, -1), (1, 0), (0, 1), (-1, 0) })
  163. {
  164. (int x, int y) successor = (node.x + mv.mx, node.y + mv.my);
  165. // Continue if no door exist
  166. if (doors.Contains((node, successor)) == false) continue;
  167. if (visitedNodes.Contains(successor)) continue;
  168. if (nodesToVisit.Contains(successor) == false)
  169. {
  170. meta.TryAdd(successor, mv);
  171. nodesToVisit.Enqueue(successor);
  172. }
  173. }
  174. visitedNodes.Add(node);
  175. }
  176. return -1;
  177. }
  178. private static int GetActionList((int x, int y) root, Dictionary<(int x, int y), (int x, int y)> meta, (int x, int y) node)
  179. {
  180. var actionList = new List<(int x, int y)>();
  181. while (meta[node] != (0, 0))
  182. {
  183. var action = meta[node];
  184. node = (node.x - action.x, node.y - action.y);
  185. actionList.Add(action);
  186. }
  187. return actionList.Count;
  188. }
  189. }
  190. }