Grid.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System.Text;
  2. namespace Day10;
  3. public class Grid
  4. {
  5. private readonly int _width;
  6. private readonly int _height;
  7. private Tile? _start;
  8. public Tile[,] Tiles { get; }
  9. public Grid(Tile[,] tiles, int width, int height)
  10. {
  11. _width = width;
  12. _height = height;
  13. Tiles = tiles;
  14. }
  15. public void Print()
  16. {
  17. for (var y = 0; y < _height; y++)
  18. {
  19. var lineBuilder = new StringBuilder();
  20. for (var x = 0; x < _width; x++)
  21. {
  22. lineBuilder.Append(Tiles[x, y].Display ?? " ");
  23. }
  24. Console.WriteLine(lineBuilder);
  25. }
  26. }
  27. public int Follow()
  28. {
  29. foreach (var t in Tiles)
  30. {
  31. if (t.Pipe == 'S')
  32. {
  33. _start = t;
  34. break;
  35. }
  36. }
  37. if (_start == null)
  38. {
  39. throw new Exception("Start is not set yet");
  40. }
  41. var queue = new Queue<(Tile Tile, GridPoint Source, int Index)>();
  42. queue.Enqueue((_start, _start.Position, 0));
  43. while (queue.Count > 0)
  44. {
  45. var (tile, source, index) = queue.Dequeue();
  46. if (tile.HasDisplay)
  47. {
  48. UpdateStart();
  49. return index;
  50. }
  51. foreach (var next in tile.GetConnections()
  52. .Where(n => n != source)
  53. .Select(x => this[x])
  54. .Where(t => t?.ConnectsTo(tile.Position) ?? false))
  55. {
  56. queue.Enqueue((next!, tile.Position, index + 1));
  57. }
  58. tile.SetDisplay(index);
  59. }
  60. throw new Exception("No cycle found");
  61. }
  62. public int Enclosed()
  63. {
  64. var enclosed = 0;
  65. for (var y = 0; y < _height; y++)
  66. {
  67. var verticals = 0;
  68. var half = 0;
  69. for (var x = 0; x < _width; x++)
  70. {
  71. var tile = Tiles[x, y];
  72. if (!tile.HasDisplay)
  73. {
  74. enclosed += (verticals % 2 == 1) ? 1 : 0;
  75. }
  76. else
  77. {
  78. switch (tile.Pipe)
  79. {
  80. case '|':
  81. verticals++;
  82. break;
  83. case 'F':
  84. case '7':
  85. half += 1;
  86. if (half == 0)
  87. {
  88. verticals++;
  89. }
  90. break;
  91. case 'J':
  92. case 'L':
  93. half -= 1;
  94. if (half == 0)
  95. {
  96. verticals++;
  97. }
  98. break;
  99. default:
  100. break;
  101. }
  102. if (Math.Abs(half) > 1)
  103. {
  104. half = 0;
  105. }
  106. }
  107. }
  108. }
  109. return enclosed;
  110. }
  111. public Tile? this[GridPoint point]
  112. {
  113. get
  114. {
  115. if (point.X < 0 || point.Y < 0 || point.X >= _width || point.Y >= _height)
  116. {
  117. return null;
  118. }
  119. return Tiles[point.X, point.Y];
  120. }
  121. }
  122. private void UpdateStart()
  123. {
  124. var outlets = _start!
  125. .GetConnections()
  126. .Select(p => this[p])
  127. .Where(t => (t?.HasDisplay ?? false) && (t.ConnectsTo(_start.Position)))
  128. .Cast<Tile>()
  129. .ToList();
  130. if (outlets.Count != 2)
  131. {
  132. throw new Exception("Only 2 outlets for S expected");
  133. }
  134. var east = outlets.Any(t => t.Position.X > _start.Position.X);
  135. var west = outlets.Any(t => t.Position.X < _start.Position.X);
  136. var north = outlets.Any(t => t.Position.Y < _start.Position.Y);
  137. var south = outlets.Any(t => t.Position.Y > _start.Position.Y);
  138. var pipe = ' ';
  139. if (north && south)
  140. {
  141. pipe = '|';
  142. }
  143. if (north && east)
  144. {
  145. pipe = 'L';
  146. }
  147. if (north && west)
  148. {
  149. pipe = 'J';
  150. }
  151. if (east && west)
  152. {
  153. pipe = '-';
  154. }
  155. if (south && east)
  156. {
  157. pipe = 'F';
  158. }
  159. if (south && west)
  160. {
  161. pipe = '7';
  162. }
  163. Tiles[_start.Position.X, _start.Position.Y] = new Tile(pipe, _start.Position);
  164. _start = Tiles[_start.Position.X, _start.Position.Y];
  165. _start.SetDisplay(0);
  166. }
  167. }