1
0

Program.cs 8.6 KB

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