Program.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. namespace D11._1
  7. {
  8. public enum EnumElement
  9. {
  10. Strontium = 0,
  11. Plutonium = 1,
  12. Thulium = 2,
  13. Ruthenium = 3,
  14. Curium = 4,
  15. Elerium = 5,
  16. Dilithium = 6
  17. }
  18. public enum EnumType
  19. {
  20. Generator = 0,
  21. Microship = 1
  22. }
  23. public class Facility : ICloneable
  24. {
  25. public Floor[] Floors { get; private set; }
  26. public int Elevator { get; set; }
  27. // All floors are empty except for the last one
  28. public bool IsOk()
  29. {
  30. for (var i = 0; i < Floors.Length - 1; ++i)
  31. if (Floors[i].IsEmpty() == false) return false;
  32. return true;
  33. }
  34. public Facility()
  35. {
  36. Floors = new Floor[4];
  37. for (var i = 0; i < 4; ++i)
  38. Floors[i] = new Floor();
  39. }
  40. public Floor CurrentFloor => Floors[Elevator];
  41. public class Floor : ICloneable
  42. {
  43. public bool[][] Objects = new bool[2][];
  44. public bool IsEmpty()
  45. {
  46. for (var i = 0; i < Objects[0].Length; ++i)
  47. if (Objects[(int)EnumType.Generator][i] || Objects[(int)EnumType.Microship][i]) return false;
  48. return true;
  49. }
  50. public bool IsValid()
  51. {
  52. int generators = 0;
  53. int unpluggedMicroships = 0;
  54. for (var i = 0; i < Objects[0].Length; ++i)
  55. {
  56. if (Objects[(int)EnumType.Generator][i]) generators++;
  57. if (Objects[(int)EnumType.Generator][i] && Objects[(int)EnumType.Microship][i]) continue;
  58. if (Objects[(int)EnumType.Microship][i]) unpluggedMicroships++;
  59. }
  60. return generators >= 0 && unpluggedMicroships == 0;
  61. }
  62. static readonly int nelement = Enum.GetValues(typeof(EnumElement)).Length;
  63. public Floor()
  64. {
  65. for (int i = 0; i < Objects.Length; ++i)
  66. Objects[i] = new bool[nelement];
  67. }
  68. public object Clone()
  69. {
  70. var floor = new Floor();
  71. for (var i = 0; i < Objects.Length; i++)
  72. for (var j = 0; j < Objects[i].Length; ++j)
  73. floor.Objects[i][j] = Objects[i][j];
  74. return floor;
  75. }
  76. public bool Set(EnumType type, EnumElement element, bool value) => Objects[(int)type][(int)element] = value;
  77. public bool Add(EnumType type, EnumElement element) => Set(type, element, true);
  78. public override bool Equals(object obj) => obj is Floor floor && floor.GetHashCode() == GetHashCode();
  79. public override int GetHashCode()
  80. {
  81. //int h1 = 0, h2 = 0;
  82. //for (var i = 0; i < Objects[0].Length; ++i)
  83. //{
  84. // h1 += (Objects[0][i] ? 1 : 0) << i;
  85. // h2 += (Objects[1][i] ? 1 : 0) << i;
  86. //}
  87. //return h1 * 100 + h2;
  88. int paired = 0, unpairedGen = 0, unpairedMicroship = 0;
  89. for (var i = 0; i < Objects[0].Length; ++i)
  90. {
  91. if (Objects[(int)EnumType.Microship][i] && Objects[(int)EnumType.Generator][i])
  92. {
  93. paired++;
  94. continue;
  95. }
  96. if (Objects[(int)EnumType.Microship][i]) unpairedMicroship++;
  97. if (Objects[(int)EnumType.Generator][i]) unpairedGen++;
  98. }
  99. return (((paired << 3) + unpairedGen) << 3) + unpairedMicroship;
  100. }
  101. }
  102. public override bool Equals(object obj) => obj is Facility facility && facility.GetHashCode() == GetHashCode() && facility.Elevator == Elevator;
  103. public override int GetHashCode()
  104. {
  105. int hash = 0;
  106. foreach (var floor in Floors) hash = HashCode.Combine(hash, floor.GetHashCode());
  107. return hash;
  108. }
  109. public object Clone()
  110. {
  111. var nf = new Facility
  112. {
  113. Elevator = this.Elevator,
  114. Floors = new Floor[Floors.Length]
  115. };
  116. for (var i = 0; i < Floors.Length; ++i) nf.Floors[i] = (Floor) Floors[i].Clone();
  117. return nf;
  118. }
  119. }
  120. class Program
  121. {
  122. static readonly EnumElement[] aelement = Enum.GetValues(typeof(EnumElement)) as EnumElement[];
  123. static void RunFacilityTest(Facility startFacility)
  124. {
  125. var upd = new [] { -1, +1 };
  126. var cmp = Comparer<(Facility, int)>.Create((a, b) => a.Item2.CompareTo(b.Item2));
  127. var queue = new Queue<(Facility facility, int step)>();
  128. var tested = new HashSet<Facility>();
  129. queue.Enqueue((startFacility, 0));
  130. while (queue.Count > 0)
  131. {
  132. (Facility facility, int step) = queue.Dequeue();
  133. if (facility.IsOk())
  134. {
  135. Console.WriteLine($"The answer is : {step}");
  136. break;
  137. }
  138. foreach (((EnumType t, EnumElement e) c1, (EnumType t, EnumElement e)? c2) in GetCandidates(facility))
  139. {
  140. foreach (var direction in upd)
  141. {
  142. if (facility.Elevator + direction < 0 || facility.Elevator + direction >= facility.Floors.Length) continue;
  143. Facility nfacility = BuildNewFacility(facility, c1, c2, direction);
  144. if (nfacility.CurrentFloor.IsValid() == false) continue;
  145. if (tested.Contains(nfacility)) continue;
  146. tested.Add(nfacility);
  147. queue.Enqueue((nfacility, step + 1));
  148. }
  149. }
  150. }
  151. }
  152. private static Facility BuildNewFacility(Facility facility, (EnumType t, EnumElement e) c1, (EnumType t, EnumElement e)? c2, int d)
  153. {
  154. var nfacility = facility.Clone() as Facility;
  155. nfacility.CurrentFloor.Objects[(int)c1.t][(int)c1.e] = false;
  156. if (c2.HasValue) nfacility.CurrentFloor.Objects[(int)c2?.t][(int)c2?.e] = false;
  157. nfacility.Elevator += d;
  158. nfacility.CurrentFloor.Objects[(int)c1.t][(int)c1.e] = true;
  159. if (c2.HasValue) nfacility.CurrentFloor.Objects[(int)c2?.t][(int)c2?.e] = true;
  160. return nfacility;
  161. }
  162. private static HashSet<((EnumType, EnumElement), (EnumType, EnumElement)?)> GetCandidates(Facility facility)
  163. {
  164. var all = new List<(EnumType, EnumElement)>();
  165. foreach (EnumElement element in aelement)
  166. {
  167. if (facility.CurrentFloor.Objects[(int)EnumType.Generator][(int)element]) all.Add((EnumType.Generator, element));
  168. if (facility.CurrentFloor.Objects[(int)EnumType.Microship][(int)element]) all.Add((EnumType.Microship, element));
  169. }
  170. var comb = new HashSet<((EnumType, EnumElement), (EnumType, EnumElement)?)>();
  171. foreach ((EnumType t1, EnumElement e1) in all)
  172. {
  173. foreach ((EnumType t2, EnumElement e2) in all)
  174. {
  175. if (t1 == t2 && e1 == e2)
  176. {
  177. comb.Add(((t1, e1), null));
  178. continue;
  179. }
  180. if (comb.Contains(((t2, e2), (t1, e1)))) continue;
  181. comb.Add(((t1, e1), (t2, e2)));
  182. }
  183. }
  184. return comb;
  185. }
  186. static void Main(string[] args)
  187. {
  188. if (args.Length < 1) throw new ArgumentException();
  189. if (File.Exists(args[0]) == false) throw new FileNotFoundException();
  190. Console.WriteLine( "=== PART 1 ========");
  191. Part1();
  192. Console.WriteLine("\n=== PART 2 ========");
  193. Part2();
  194. }
  195. private static void Part1()
  196. {
  197. var facility = new Facility();
  198. BaseFacility(facility);
  199. var sw = Stopwatch.StartNew();
  200. RunFacilityTest(facility);
  201. sw.Stop();
  202. Console.WriteLine($"\nExecution time : {sw.ElapsedMilliseconds}ms");
  203. }
  204. private static void BaseFacility(Facility facility)
  205. {
  206. facility.Floors[0].Add(EnumType.Generator, EnumElement.Strontium);
  207. facility.Floors[0].Add(EnumType.Microship, EnumElement.Strontium);
  208. facility.Floors[0].Add(EnumType.Generator, EnumElement.Plutonium);
  209. facility.Floors[0].Add(EnumType.Microship, EnumElement.Plutonium);
  210. facility.Floors[1].Add(EnumType.Generator, EnumElement.Thulium);
  211. facility.Floors[1].Add(EnumType.Generator, EnumElement.Ruthenium);
  212. facility.Floors[1].Add(EnumType.Microship, EnumElement.Ruthenium);
  213. facility.Floors[1].Add(EnumType.Generator, EnumElement.Curium);
  214. facility.Floors[1].Add(EnumType.Microship, EnumElement.Curium);
  215. facility.Floors[2].Add(EnumType.Microship, EnumElement.Thulium);
  216. }
  217. private static void Part2()
  218. {
  219. var facility = new Facility();
  220. BaseFacility(facility);
  221. facility.Floors[0].Add(EnumType.Generator, EnumElement.Elerium);
  222. facility.Floors[0].Add(EnumType.Microship, EnumElement.Elerium);
  223. facility.Floors[0].Add(EnumType.Generator, EnumElement.Dilithium);
  224. facility.Floors[0].Add(EnumType.Microship, EnumElement.Dilithium);
  225. var sw = Stopwatch.StartNew();
  226. RunFacilityTest(facility);
  227. sw.Stop();
  228. Console.WriteLine($"\nExecution time : {sw.ElapsedMilliseconds}ms");
  229. }
  230. }
  231. }