Cawa245

Untitled

May 2nd, 2019
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.83 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using Greedy.Architecture;
  6. using Greedy.Architecture.Drawing;
  7.  
  8. namespace Greedy
  9. {
  10. public class NotGreedyPathFinder : IPathFinder
  11. {
  12. public const int Limiter = 8;
  13.  
  14. private static State _state;
  15. private static readonly Dictionary<Edge, double> Weights = new Dictionary<Edge, double>();
  16. public List<Point> FindPathToCompleteGoal(State state)
  17. {
  18. _state = state;
  19. var graph = new Graph(state.MapHeight * state.MapWidth);
  20. var chests = state.Chests.Take(Limiter);
  21. var bestPath = new List<Point>();
  22. var pathsBetweenChests = new Dictionary<Point, Dictionary<Point, List<Point>>>();
  23.  
  24. InitializeGraphOnCells(graph);
  25. pathsBetweenChests[state.Position] = GetPathToChests(graph, state.Position);
  26.  
  27. var points = chests as List<Point> ?? chests.ToList();
  28. points.ToList().ForEach(chest =>
  29. {
  30. pathsBetweenChests[chest] = GetPathToChests(graph, chest);
  31. });
  32.  
  33. for (var i = 1; i <= Limiter; i++)
  34. {
  35. var reachableChestPermutations =
  36. GetPermutations(points, i)
  37. .Where(perm => PathsStaminaCost(perm, pathsBetweenChests) <= state.Energy);
  38.  
  39. var chestPermutations = reachableChestPermutations.ToList();
  40. if (!chestPermutations.ToArray().Any()) break;
  41. bestPath = chestPermutations.ToArray()
  42. .First()
  43. .ToList();
  44. }
  45.  
  46. return GetTotalPath(state, bestPath, pathsBetweenChests);
  47. }
  48.  
  49. private static Dictionary<Point, List<Point>> GetPathToChests(Graph graph, Point start)
  50. {
  51. var result = new Dictionary<Point, List<Point>>();
  52. var chests = _state.Chests.Where(chest => chest != start);
  53. chests.ToList().ForEach(chest => { result[chest] = GetPathToChest(graph, start, chest); });
  54. return result;
  55. }
  56.  
  57. private static List<Point> GetPathToChest(Graph graph,Point start, Point chest)
  58. {
  59. var initialPositionNumber = start.X + start.Y * _state.MapWidth;
  60. var chestPositionNumber = chest.X + chest.Y * _state.MapWidth;
  61. var path = Dijkstra(graph, graph[initialPositionNumber], graph[chestPositionNumber]);
  62. return path?.Select(n => new Point(n.Number % _state.MapWidth, n.Number / _state.MapWidth))
  63. .Skip(1)
  64. .ToList() ?? new List<Point>();
  65. }
  66.  
  67. private static int PathsStaminaCost(IEnumerable<Point> chests,
  68. IReadOnlyDictionary<Point, Dictionary<Point, List<Point>>> pathsBetweenChests)
  69. {
  70. var current = _state.Position;
  71. var total = 0;
  72.  
  73. chests.ToList().ForEach(chest =>
  74. {
  75. total += pathsBetweenChests[current][chest].Sum(point => _state.CellCost[point.X, point.Y]);
  76. current = chest;
  77. });
  78.  
  79. return total;
  80. }
  81.  
  82. private static List<Point> GetTotalPath(State state, IEnumerable<Point> pointsPermutation,
  83. IReadOnlyDictionary<Point, Dictionary<Point, List<Point>>> pathsBetweenChests)
  84. {
  85. var current = state.Position;
  86. var result = new List<Point>();
  87.  
  88. pointsPermutation.ToList().ForEach(point =>
  89. {
  90. result.AddRange(pathsBetweenChests[current][point]);
  91. current = point;
  92. });
  93. return result;
  94. }
  95.  
  96. private static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
  97. {
  98. if (length == 1) return list.Select(t => new[] {t});
  99. var enumerable = list.ToList();
  100. return GetPermutations(enumerable, length - 1)
  101. .SelectMany(t =>
  102. enumerable.Where(o => !t.Contains(o)),
  103. (t1, t2) => t1.Concat(new[] {t2}));
  104. }
  105.  
  106. private static void InitializeGraphOnCells(Graph graph)
  107. {
  108. for (var y = 0; y < _state.MapHeight; y++)
  109. for (var x = 0; x < _state.MapWidth; x++)
  110. {
  111. var point = new Point(x, y);
  112. var pointsList = new List<Point>
  113. {
  114. new Point(x, y - 1),
  115. new Point(x, y + 1),
  116. new Point(x + 1, y),
  117. new Point(x - 1, y)
  118. };
  119. pointsList.ForEach(newPoint =>
  120. {
  121. if (!_state.InsideMap(newPoint) || _state.IsWallAt(newPoint)) return;
  122. var pointNumber = point.X + point.Y * _state.MapWidth;
  123. var neighbourNumber = newPoint.X + newPoint.Y * _state.MapWidth;
  124. Weights[graph.Connect(pointNumber, neighbourNumber)] = _state.CellCost[newPoint.X, newPoint.Y];
  125. });
  126. }
  127. }
  128.  
  129. private static IEnumerable<Node> Dijkstra(Graph graph, Node start, Node end)
  130. {
  131. var notVisited = graph.Nodes.ToList();
  132. var track = new Dictionary<Node, DijkstraData>
  133. {
  134. [start] = new DijkstraData
  135. {
  136. Price = 0,
  137. Previous = null
  138. }
  139. };
  140.  
  141. Node toOpen = null;
  142.  
  143. while (toOpen != end)
  144. {
  145. var bestPrice = double.PositiveInfinity;
  146. toOpen = null;
  147. notVisited.ForEach(e =>
  148. {
  149. if (!track.ContainsKey(e) || !(track[e].Price < bestPrice)) return;
  150. bestPrice = track[e].Price;
  151. toOpen = e;
  152. });
  153. if (toOpen == null) return null;
  154. toOpen.IncidentEdges
  155. .Where(z => z.Output == toOpen)
  156. .ToList()
  157. .ForEach(e =>
  158. {
  159. var currentPrice = track[toOpen].Price + Weights[e];
  160. var nextNode = e.OtherNode(toOpen);
  161. if (!track.ContainsKey(nextNode)
  162. || track[nextNode].Price > currentPrice)
  163. track[nextNode] = new DijkstraData
  164. {
  165. Previous = toOpen,
  166. Price = currentPrice
  167. };
  168. });
  169. notVisited.Remove(toOpen);
  170. }
  171.  
  172. var result = new List<Node>();
  173.  
  174. while (end != null)
  175. {
  176. result.Add(end);
  177. end = track[end].Previous;
  178. }
  179.  
  180. result.Reverse();
  181. return result;
  182. }
  183.  
  184. internal class DijkstraData
  185. {
  186. public Node Previous { get; set; }
  187. public double Price { get; set; }
  188. }
  189.  
  190. internal class Edge
  191. {
  192. public readonly Node Output;
  193. public readonly Node Input;
  194.  
  195. public Edge(Node output, Node input)
  196. {
  197. Output = output;
  198. Input = input;
  199. }
  200.  
  201. public bool IsIncident(Node node)
  202. {
  203. return Output == node || Input == node;
  204. }
  205.  
  206. public Node OtherNode(Node node)
  207. {
  208. if (!IsIncident(node)) throw new ArgumentException();
  209. return Output == node ? Input : Output;
  210. }
  211. }
  212.  
  213. internal class Node
  214. {
  215. private readonly List<Edge> edges = new List<Edge>();
  216. public int Number;
  217. public IEnumerable<Edge> IncidentEdges => edges;
  218.  
  219. public static Edge Connect(Node node1, Node node2, Graph graph)
  220. {
  221. if (!graph.Nodes.Contains(node1) || !graph.Nodes.Contains(node2)) throw new ArgumentException();
  222. var edge = new Edge(node1, node2);
  223. node1.edges.Add(edge);
  224. return edge;
  225. }
  226. }
  227.  
  228. internal class Graph
  229. {
  230. private readonly Node[] nodes;
  231. public Node this[int index] => nodes[index];
  232. public IEnumerable<Node> Nodes => nodes;
  233.  
  234. public Graph(int nodesCount)
  235. {
  236. nodes = Enumerable.Range(0, nodesCount)
  237. .Select(z => new Node {Number = z})
  238. .ToArray();
  239. }
  240.  
  241. public Edge Connect(int index1, int index2)
  242. {
  243. return Node.Connect(nodes[index1], nodes[index2], this);
  244. }
  245. }
  246. }
  247. }
Advertisement
Add Comment
Please, Sign In to add comment