Program.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. namespace D22._2
  7. {
  8. class Program
  9. {
  10. enum EnumTool
  11. {
  12. Neither,
  13. Torch,
  14. Climbing
  15. }
  16. enum EnumTerrain
  17. {
  18. Rocky = 0,
  19. Wet = 1,
  20. Narrow = 2
  21. }
  22. static readonly Dictionary<EnumTerrain, EnumTool[]> AuthTool = new Dictionary<EnumTerrain, EnumTool[]>
  23. {
  24. { EnumTerrain.Rocky, new [] { EnumTool.Torch, EnumTool.Climbing } },
  25. { EnumTerrain.Wet, new [] { EnumTool.Climbing, EnumTool.Neither } },
  26. { EnumTerrain.Narrow, new [] { EnumTool.Torch, EnumTool.Neither } },
  27. };
  28. static (int mx, int my)[] MoveSequence = new[] { (0, -1), (-1, 0), (1, 0), (0, 1) };
  29. static int Manhattan((int x, int y) a, (int x, int y) b)
  30. {
  31. return Math.Abs(a.x - b.x) + Math.Abs(a.y - b.y);
  32. }
  33. static int UniformCostSearch((int x, int y) start, (int x, int y) goal, int depth)
  34. {
  35. var node = start;
  36. EnumTool tool = EnumTool.Torch;
  37. int cost = 0;
  38. var frontier = new List<((int x, int y) node, int cost, EnumTool tool)>();
  39. var explored = new HashSet<((int x, int y), EnumTool tool)>();
  40. frontier.Add((node, cost, tool));
  41. while (frontier.Count > 0)
  42. {
  43. frontier.Sort((a, b) => a.cost.CompareTo(b.cost));
  44. var q = frontier.First();
  45. frontier.RemoveAt(0);
  46. cost = q.cost;
  47. node = q.node;
  48. tool = q.tool;
  49. var terrain = graph[node];
  50. if (node == goal && tool == EnumTool.Torch) return cost;
  51. explored.Add((node, tool));
  52. foreach (var ntool in AuthTool[terrain])
  53. {
  54. if (ntool == tool) continue;
  55. if (explored.Contains((node, ntool)) == true) continue;
  56. frontier.Add((node, cost + 7, ntool));
  57. }
  58. foreach (var (mx, my) in MoveSequence)
  59. {
  60. (int x, int y) n = (node.x + mx, node.y + my);
  61. if (n.x < 0 || n.y < 0 || n.x > goal.x + 15 || n.y > goal.y + 50) continue;
  62. if (explored.Contains((n, tool)) == true) continue;
  63. if (graph.ContainsKey(n) == false)
  64. ExtendMap(depth, goal, n);
  65. var nterrain = graph[n];
  66. if (AuthTool[nterrain].Contains(tool) == false) continue;
  67. if (frontier.Contains((n, cost + 1, tool)) == false)
  68. {
  69. frontier.RemoveAll(f => f.node == n && f.cost > cost + 1);
  70. frontier.Add((n, cost + 1, tool));
  71. }
  72. }
  73. }
  74. return -1;
  75. }
  76. static Dictionary<(int, int), int> erosionLevels = new Dictionary<(int, int), int>();
  77. static Dictionary<(int, int), EnumTerrain> graph = new Dictionary<(int, int), EnumTerrain>();
  78. static void Main(string[] args)
  79. {
  80. if (args.Length < 1) return;
  81. if (File.Exists(args[0]) == false) return;
  82. var file = File.OpenText(args[0]);
  83. int depth = int.Parse(file.ReadLine().Substring("depth: ".Length));
  84. int[] arrayCoord = file.ReadLine().Substring("target: ".Length).Split(",").Select(s => int.Parse(s)).ToArray();
  85. (int x, int y) coord = (arrayCoord[0], arrayCoord[1]);
  86. file.Close();
  87. ExtendMap(depth, (0, 0), (0, 0));
  88. var sw = Stopwatch.StartNew();
  89. var cost = UniformCostSearch((0, 0), coord, depth);
  90. sw.Stop();
  91. Console.WriteLine(sw.ElapsedMilliseconds);
  92. Console.WriteLine($"Shortest path costs {cost} minutes");
  93. }
  94. private static void ExtendMap(int depth, (int x, int y) coord, (int x, int y) extension)
  95. {
  96. ComputeRisk(coord, extension, depth);
  97. }
  98. private static void ComputeRisk((int x, int y) coord, (int x, int y) pos, int depth)
  99. {
  100. int geo = 0;
  101. if (pos != (0, 0) && pos != coord)
  102. {
  103. if (pos.x == 0) geo = pos.y * 48271;
  104. else if (pos.y == 0) geo = pos.x * 16807;
  105. else
  106. {
  107. if (erosionLevels.ContainsKey((pos.x - 1, pos.y)) == false) ComputeRisk(coord, (pos.x - 1, pos.y), depth);
  108. if (erosionLevels.ContainsKey((pos.x, pos.y - 1)) == false) ComputeRisk(coord, (pos.x, pos.y - 1), depth);
  109. geo = erosionLevels[(pos.x - 1, pos.y)] * erosionLevels[(pos.x, pos.y - 1)];
  110. }
  111. }
  112. int ero = (geo + depth) % 20183;
  113. EnumTerrain type = (EnumTerrain) (ero % 3);
  114. erosionLevels.Add(pos, ero);
  115. graph.Add(pos, type);
  116. }
  117. }
  118. }