Program.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. using Accord.Video.FFMPEG;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text.RegularExpressions;
  9. namespace D17.Bonus
  10. {
  11. class Program
  12. {
  13. enum EnumType
  14. {
  15. Clay, StillWater, RunningWater
  16. }
  17. static int panY = 0;
  18. static void Main(string[] args)
  19. {
  20. if (args.Length < 1) return;
  21. if (File.Exists(args[0]) == false) return;
  22. var file = File.OpenText(args[0]);
  23. var reg = new Regex(@"[xy]=(\d+), [xy]=(\d+)[.][.](\d+)");
  24. var map = new Dictionary<(int x, int y), EnumType>();
  25. var rwater = new Accord.Collections.OrderedDictionary<(int x, int y), (int x, int y)>();
  26. int MAXY = 0;
  27. int MINX = int.MaxValue;
  28. int MINY = int.MaxValue;
  29. int MAXX = 0;
  30. do
  31. {
  32. var line = file.ReadLine();
  33. if (line == null) break;
  34. var result = reg.Match(line);
  35. CreateMap(map, ref MAXY, ref MINX, ref MINY, ref MAXX, line, result);
  36. } while (true);
  37. file.Close();
  38. // Start with river
  39. rwater.Add((500, 0), (500, 0));
  40. map.Add((500, 0), EnumType.RunningWater);
  41. Console.SetOut(TextWriter.Null);
  42. VideoFileWriter writer = new VideoFileWriter();
  43. var width = MAXX - MINX + 2;
  44. if (width % 2 == 1) width++;
  45. var height = (width * 3) / 4;
  46. if (height % 2 == 1) height++;
  47. int tpy = (height * 2) / 3;
  48. writer.Open("out.avi", width, height);
  49. int rr = 0;
  50. while (rwater.Count > 0)
  51. {
  52. rr++;
  53. if (rwater.Any(r => r.Key.y > panY + tpy)) panY++;
  54. var enumer = rwater.FirstOrDefault();
  55. var water = enumer.Key;
  56. var source = enumer.Value;
  57. if (map.ContainsKey((water.x, water.y + 1)) == false && water.y > MAXY)
  58. {
  59. rwater.Remove(water);
  60. continue;
  61. }
  62. bool renderMap = false;
  63. if (map.ContainsKey((water.x, water.y + 1)) == false || map[(water.x, water.y + 1)] == EnumType.RunningWater)
  64. {
  65. RaindropsOnRoses(map, rwater, water);
  66. renderMap = true;
  67. }
  68. else
  69. {
  70. ExpandToBothSides(map, rwater, water, source);
  71. renderMap = true;
  72. int maxX, minX;
  73. bool canConvert = CanConvertToStillWater(map, rwater, water, source, out maxX, out minX);
  74. if (canConvert)
  75. ConvertToStillWater(map, rwater, water, source, maxX, minX);
  76. else
  77. rwater.Remove(water);
  78. }
  79. if (renderMap)
  80. {
  81. if (rr < rwater.Count) continue;
  82. RenderMap(map, writer, MINX, MAXY, width, height);
  83. rr = 1;
  84. }
  85. }
  86. var lastBitmap = RenderMap(map, writer, MINX, MAXY, width, height);
  87. var countEx1 = map.Count(m => (m.Key.y >= MINY && m.Key.y <= MAXY) && (m.Value == EnumType.RunningWater || m.Value == EnumType.StillWater));
  88. var countEx2 = map.Count(m => (m.Key.y >= MINY && m.Key.y <= MAXY) && (m.Value == EnumType.StillWater));
  89. var answer = $"The answer is {countEx1}m3 flooded,\n and {countEx2}m3 still water ☺";
  90. using (var gd = Graphics.FromImage(lastBitmap))
  91. using (var font = new Font(FontFamily.GenericSerif, 12, FontStyle.Regular))
  92. {
  93. gd.DrawString(answer, font, Brushes.IndianRed, 10, tpy + 10);
  94. writer.WriteVideoFrame(lastBitmap);
  95. }
  96. }
  97. private static void RaindropsOnRoses(Dictionary<(int x, int y), EnumType> map, IDictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water)
  98. {
  99. rwater.Remove(water);
  100. var drop = (water.x, water.y + 1);
  101. if (!rwater.ContainsKey(drop)) rwater.Add(drop, water);
  102. map[drop] = EnumType.RunningWater;
  103. }
  104. private static void ConvertToStillWater(Dictionary<(int x, int y), EnumType> map, IDictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water, (int x, int y) source, int maxX, int minX)
  105. {
  106. for (var x = minX; x <= maxX; ++x)
  107. {
  108. var res = map.TryGetValue((x, water.y), out var type);
  109. if (type == EnumType.RunningWater)
  110. {
  111. map[(x, water.y)] = EnumType.StillWater;
  112. rwater.Remove((x, water.y));
  113. }
  114. }
  115. rwater.Remove(water);
  116. if (!rwater.ContainsKey(source)) rwater.Add(source, (source.x, source.y - 1));
  117. }
  118. private static bool CanConvertToStillWater(Dictionary<(int x, int y), EnumType> map, IDictionary<(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)
  119. {
  120. bool canConvert = true;
  121. maxX = 0;
  122. minX = 0;
  123. for (int x = water.x; canConvert; ++x) // left to right
  124. {
  125. maxX = x;
  126. var res = map.TryGetValue((x, water.y), out var type);
  127. if (res == false)
  128. {
  129. canConvert = false;
  130. if (!rwater.ContainsKey((x - 1, water.y))) rwater.Add((x - 1, water.y), source);
  131. }
  132. else if (type == EnumType.Clay) break;
  133. }
  134. for (int x = water.x; canConvert; --x) // right to left
  135. {
  136. minX = x;
  137. var res = map.TryGetValue((x, water.y), out var type);
  138. if (res == false)
  139. {
  140. canConvert = false;
  141. if (!rwater.ContainsKey((x + 1, water.y))) rwater.Add((x + 1, water.y), source);
  142. }
  143. else if (type == EnumType.Clay) break;
  144. }
  145. return canConvert;
  146. }
  147. private static void ExpandToBothSides(Dictionary<(int x, int y), EnumType> map, IDictionary<(int x, int y), (int x, int y)> rwater, (int x, int y) water, (int x, int y) source)
  148. {
  149. var next = water;
  150. while (true)
  151. {
  152. var last = next;
  153. next = (last.x - 1, water.y);
  154. var res = map.TryGetValue((next.x, water.y), out var value);
  155. if (res && value == EnumType.Clay) break;
  156. rwater.Remove(last);
  157. if (!rwater.ContainsKey(next)) rwater.Add(next, source);
  158. map[next] = EnumType.RunningWater;
  159. var hasBottom = map.TryGetValue((next.x, next.y + 1), out var bottom);
  160. if (hasBottom == false || bottom == EnumType.RunningWater)
  161. break;
  162. }
  163. next = water;
  164. while (true)
  165. {
  166. var last = next;
  167. next = (last.x + 1, water.y);
  168. var res = map.TryGetValue((next.x, water.y), out var value);
  169. if (res && value == EnumType.Clay) break;
  170. rwater.Remove(last);
  171. if (!rwater.ContainsKey(next)) rwater.Add(next, source);
  172. map[next] = EnumType.RunningWater;
  173. var hasBottom = map.TryGetValue((next.x, next.y + 1), out var bottom);
  174. if (hasBottom == false || bottom == EnumType.RunningWater)
  175. break;
  176. }
  177. }
  178. private static void CreateMap(IDictionary<(int x, int y), EnumType> map, ref int MAXY, ref int MINX, ref int MINY, ref int MAXX, string line, Match result)
  179. {
  180. var c1 = int.Parse(result.Groups[1].Value);
  181. var rmin = int.Parse(result.Groups[2].Value);
  182. var rmax = int.Parse(result.Groups[3].Value);
  183. if (line.StartsWith("x"))
  184. {
  185. if (c1 > MAXX) MAXX = c1;
  186. if (c1 < MINX) MINX = c1;
  187. }
  188. else
  189. {
  190. if (c1 > MAXY) MAXY = c1;
  191. if (c1 < MINY) MINY = c1;
  192. }
  193. for (int i = rmin; i <= rmax; ++i)
  194. {
  195. if (line.StartsWith("x"))
  196. {
  197. if (i > MAXY) MAXY = i;
  198. if (i < MINY) MINY = i;
  199. map[(c1, i)] = EnumType.Clay;
  200. }
  201. else
  202. {
  203. if (i > MAXX) MAXX = i;
  204. if (i < MINX) MINX = i;
  205. map[(i, c1)] = EnumType.Clay;
  206. }
  207. }
  208. }
  209. static Bitmap _REFBMP = null;
  210. private static Bitmap RenderMap(Dictionary<(int x, int y), EnumType> map, VideoFileWriter writer, int MINX, int MAXY, int width, int height)
  211. {
  212. if (_REFBMP == null)
  213. {
  214. _REFBMP = new Bitmap(width, height);
  215. for (int x = 0; x < width; ++x)
  216. for (int y = 0; y < height; ++y)
  217. _REFBMP.SetPixel(x, y, Color.FloralWhite);
  218. }
  219. var bmp = new Bitmap(_REFBMP);
  220. var hh = Math.Min(height + panY, MAXY);
  221. var sortedMap = map.OrderBy(m => m.Key.y).Where(m => m.Key.y > panY && m.Key.y <= hh);
  222. foreach (var res in sortedMap)
  223. {
  224. var type = res.Value;
  225. var px = res.Key.x - MINX + 1;
  226. var py = res.Key.y - panY - 1;
  227. if (type == EnumType.Clay) bmp.SetPixel(px, py, Color.Maroon);
  228. else if (type == EnumType.RunningWater) bmp.SetPixel(px, py, Color.Aqua);
  229. else if (type == EnumType.StillWater) bmp.SetPixel(px, py, Color.Aquamarine);
  230. }
  231. writer.WriteVideoFrame(bmp);
  232. return bmp;
  233. }
  234. }
  235. }