Program.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6. namespace D17._1
  7. {
  8. class Program
  9. {
  10. enum EnumType
  11. {
  12. Clay, StillWater, RunningWater
  13. }
  14. static void Main(string[] args)
  15. {
  16. if (args.Length < 1) return;
  17. if (File.Exists(args[0]) == false) return;
  18. var file = File.OpenText(args[0]);
  19. var reg = new Regex(@"[xy]=(\d+), [xy]=(\d+)[.][.](\d+)");
  20. var map = new Dictionary<(int x, int y), EnumType>();
  21. var rwater = new Dictionary<(int x, int y), (int x, int y)>();
  22. int MAXY = 0;
  23. int MINX = int.MaxValue;
  24. int MINY = int.MaxValue;
  25. int MAXX = 0;
  26. do
  27. {
  28. var line = file.ReadLine();
  29. if (line == null) break;
  30. var result = reg.Match(line);
  31. CreateMap(map, ref MAXY, ref MINX, ref MINY, ref MAXX, line, result);
  32. } while (true);
  33. // Start with river
  34. rwater.Add((500, 0), (500, 0));
  35. map.Add((500, 0), EnumType.RunningWater);
  36. while (rwater.Count > 0)
  37. {
  38. //PrintMap(map, MINX, MAXX, MAXY);
  39. var enumer = rwater.FirstOrDefault();
  40. var water = enumer.Key;
  41. var source = enumer.Value;
  42. if (map.ContainsKey((water.x, water.y + 1)) == false && water.y + 1 > MAXY)
  43. {
  44. rwater.Remove(water);
  45. continue;
  46. }
  47. if (map.ContainsKey((water.x, water.y + 1)) == false || map[(water.x, water.y + 1)] == EnumType.RunningWater)
  48. {
  49. RaindropsOnRoses(map, rwater, water);
  50. }
  51. else
  52. {
  53. ExpandToBothSides(map, rwater, water, source);
  54. int maxX, minX;
  55. bool canConvert = CanConvertToStillWater(map, rwater, water, source, out maxX, out minX);
  56. if (canConvert)
  57. ConvertToStillWater(map, rwater, water, source, maxX, minX);
  58. else
  59. rwater.Remove(water);
  60. }
  61. }
  62. PrintMap(map, MINX, MAXX, MAXY);
  63. var countEx1 = map.Count(m => (m.Key.y >= MINY && m.Key.y <= MAXY) && (m.Value == EnumType.RunningWater || m.Value == EnumType.StillWater));
  64. var countEx2 = map.Count(m => (m.Key.y >= MINY && m.Key.y <= MAXY) && (m.Value == EnumType.StillWater));
  65. Console.WriteLine($"The answer is {countEx1} flooded tiles, {countEx2}m3 still water");
  66. }
  67. private static void RaindropsOnRoses(Dictionary<(int x, int y), EnumType> map, Dictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water)
  68. {
  69. rwater.Remove(water);
  70. rwater.TryAdd((water.x, water.y + 1), water);
  71. map.TryAdd((water.x, water.y + 1), EnumType.RunningWater);
  72. }
  73. private static void ConvertToStillWater(Dictionary<(int x, int y), EnumType> map, Dictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water, (int x, int y) source, int maxX, int minX)
  74. {
  75. for (var x = minX; x <= maxX; ++x)
  76. {
  77. var res = map.TryGetValue((x, water.y), out var type);
  78. if (type == EnumType.RunningWater)
  79. {
  80. map[(x, water.y)] = EnumType.StillWater;
  81. rwater.Remove((x, water.y));
  82. }
  83. }
  84. rwater.Remove(water);
  85. rwater.TryAdd(source, (source.x, source.y - 1));
  86. }
  87. private static bool CanConvertToStillWater(Dictionary<(int x, int y), EnumType> map, Dictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water, (int x, int y) source, out int maxX, out int minX)
  88. {
  89. bool canConvert = true;
  90. maxX = 0;
  91. minX = 0;
  92. for (int x = water.x; canConvert; ++x) // left to right
  93. {
  94. maxX = x;
  95. var res = map.TryGetValue((x, water.y), out var type);
  96. if (res == false)
  97. {
  98. canConvert = false;
  99. rwater.TryAdd((x - 1, water.y), source);
  100. }
  101. else if (type == EnumType.Clay) break;
  102. }
  103. for (int x = water.x; canConvert; --x) // right to left
  104. {
  105. minX = x;
  106. var res = map.TryGetValue((x, water.y), out var type);
  107. if (res == false)
  108. {
  109. canConvert = false;
  110. rwater.TryAdd((x + 1, water.y), source);
  111. }
  112. else if (type == EnumType.Clay) break;
  113. }
  114. return canConvert;
  115. }
  116. private static void ExpandToBothSides(Dictionary<(int x, int y), EnumType> map, Dictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water, (int x, int y) source)
  117. {
  118. var next = water;
  119. while (true)
  120. {
  121. var last = next;
  122. next = (last.x - 1, water.y);
  123. var res = map.TryGetValue((next.x, water.y), out var value);
  124. if (res && value == EnumType.Clay) break;
  125. rwater.Remove(last);
  126. rwater.TryAdd(next, source);
  127. map.TryAdd(next, EnumType.RunningWater);
  128. var hasBottom = map.TryGetValue((next.x, next.y + 1), out var bottom);
  129. if (hasBottom == false || bottom == EnumType.RunningWater)
  130. break;
  131. }
  132. next = water;
  133. while (true)
  134. {
  135. var last = next;
  136. next = (last.x + 1, water.y);
  137. var res = map.TryGetValue((next.x, water.y), out var value);
  138. if (res && value == EnumType.Clay) break;
  139. rwater.Remove(last);
  140. rwater.TryAdd(next, source);
  141. map.TryAdd(next, EnumType.RunningWater);
  142. var hasBottom = map.TryGetValue((next.x, next.y + 1), out var bottom);
  143. if (hasBottom == false || bottom == EnumType.RunningWater)
  144. break;
  145. }
  146. }
  147. private static void CreateMap(Dictionary<(int x, int y), EnumType> map, ref int MAXY, ref int MINX, ref int MINY, ref int MAXX, string line, Match result)
  148. {
  149. var c1 = int.Parse(result.Groups[1].Value);
  150. var rmin = int.Parse(result.Groups[2].Value);
  151. var rmax = int.Parse(result.Groups[3].Value);
  152. if (line.StartsWith("x"))
  153. {
  154. if (c1 > MAXX) MAXX = c1;
  155. if (c1 < MINX) MINX = c1;
  156. }
  157. else
  158. {
  159. if (c1 > MAXY) MAXY = c1;
  160. if (c1 < MINY) MINY = c1;
  161. }
  162. for (int i = rmin; i <= rmax; ++i)
  163. {
  164. if (line.StartsWith("x"))
  165. {
  166. if (i > MAXY) MAXY = i;
  167. if (i < MINY) MINY = i;
  168. map.TryAdd((c1, i), EnumType.Clay);
  169. }
  170. else
  171. {
  172. if (i > MAXX) MAXX = i;
  173. if (i < MINX) MINX = i;
  174. map.TryAdd((i, c1), EnumType.Clay);
  175. }
  176. }
  177. }
  178. private static void PrintMap(Dictionary<(int x, int y), EnumType> map, int MINX, int MAXX, int MAXY)
  179. {
  180. var std = Console.Out;
  181. var file = File.CreateText("out.txt");
  182. Console.SetOut(file);
  183. Console.SetCursorPosition(0, 0);
  184. for (int y = 0; y <= MAXY; ++y)
  185. {
  186. for (int x = MINX - 1; x <= MAXX + 1; ++x)
  187. {
  188. var res = map.TryGetValue((x, y), out var type);
  189. if (res == false) Console.Write(".");
  190. else if (type == EnumType.Clay) Console.Write("#");
  191. else if (type == EnumType.RunningWater) Console.Write("|");
  192. else if (type == EnumType.StillWater) Console.Write("~");
  193. }
  194. Console.WriteLine();
  195. }
  196. Console.SetOut(std);
  197. file.Flush();
  198. file.Close();
  199. }
  200. }
  201. }