daily pastebin goal
41%
SHARE
TWEET

Untitled

a guest Jan 29th, 2018 57 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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 GreedyPathFinder : IPathFinder
  11.     {
  12.         public List<Point> FindPathToCompleteGoal(State state)
  13.         {
  14.             var graph = new Graph(state.MapHeight * state.MapWidth);
  15.             var weights = new Dictionary<Edge, double>();
  16.  
  17.             // В задаче дан граф-сетка. Чтобы не вдаваться в конкретику, а работать с удобной абстракцией
  18.             // по сетке строится взвешеный ориентированный граф, заданный списками связности.
  19.             InitializeGraphOnCells(state, weights, graph);
  20.  
  21.             var currentPosition = state.Position;
  22.             var pathToCompleteGoal = new List<Point>();
  23.             var takedChests = new List<Point>();
  24.  
  25.             for (var i = 0; i < state.Goal; i++)
  26.             {
  27.                 var toNearestCheast = state.Chests
  28.                     .Where(chest => !takedChests.Contains(chest))
  29.                     .Select(chest => GetPathToChest(graph, weights, state, currentPosition, chest))
  30.                     .OrderBy(path => PathStaminaCost(state, path))
  31.                     .FirstOrDefault();
  32.  
  33.                 if (toNearestCheast == null || !toNearestCheast.Any())
  34.                     return new List<Point>();
  35.  
  36.                 var takedChest = toNearestCheast[toNearestCheast.Count - 1];
  37.                 takedChests.Add(takedChest);
  38.  
  39.                 currentPosition = takedChest;
  40.  
  41.                 pathToCompleteGoal.AddRange(toNearestCheast);
  42.             }
  43.  
  44.             return PathStaminaCost(state, pathToCompleteGoal) <= state.Energy
  45.                 ? pathToCompleteGoal
  46.                 : new List<Point>();
  47.         }
  48.  
  49.         private static List<Point> GetPathToChest(Graph graph, Dictionary<Edge, double> weights,
  50.             State state, Point start, Point chest)
  51.         {
  52.             var initialPositionNumber = GetPointNumber(start, state.MapWidth);
  53.             var chestPositionNumber = GetPointNumber(chest, state.MapWidth);
  54.  
  55.             var path = Dijkstra(graph, weights, graph[initialPositionNumber], graph[chestPositionNumber]);
  56.  
  57.             return path?.Select(n => CreatePointByNumber(n.NodeNumber, state.MapWidth)).Skip(1).ToList() ??
  58.                    new List<Point>();
  59.         }
  60.  
  61.         private static int PathStaminaCost(State state, IEnumerable<Point> path)
  62.         {
  63.             return path.Sum(point => state.CellCost[point.X, point.Y]);
  64.         }
  65.  
  66.         private static void InitializeGraphOnCells(State state, IDictionary<Edge, double> weights, Graph graph)
  67.         {
  68.             for (var y = 0; y < state.MapHeight; y++)
  69.             for (var x = 0; x < state.MapWidth; x++)
  70.             {
  71.                 var point = new Point(x, y);
  72.  
  73.                 for (var dy = -1; dy <= 1; dy++)
  74.                 for (var dx = -1; dx <= 1; dx++)
  75.                 {
  76.                     if (dx != 0 && dy != 0) continue;
  77.                     var neighbour = new Point(x + dx, y + dy);
  78.                     if (!state.InsideMap(neighbour)) continue;
  79.                     if (state.IsWallAt(neighbour)) continue;
  80.  
  81.                     var pointNumber = GetPointNumber(point, state.MapWidth);
  82.                     var neighbourNumber = GetPointNumber(neighbour, state.MapWidth);
  83.                     weights[graph.Connect(pointNumber, neighbourNumber)] = state.CellCost[neighbour.X, neighbour.Y];
  84.                 }
  85.             }
  86.         }
  87.  
  88.         private static int GetPointNumber(Point point, int mapWidth)
  89.         {
  90.             return point.Y * mapWidth + point.X;
  91.         }
  92.  
  93.         private static Point CreatePointByNumber(int pointNumber, int mapWidth)
  94.         {
  95.             return new Point(pointNumber % mapWidth, pointNumber / mapWidth);
  96.         }
  97.  
  98.         // (づ°ω°)づミe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
  99.         // Весь остальной код взят из материалов лекций с минимумом изменений.
  100.         // Изменение 1: метод Connect теперь работает как на ориентированном графе
  101.         // (раньше он добавлял ребро в обе стороны).
  102.         // Изменение 2: удалил методы Disconnect.
  103.         // Изменение 3: классы описывающие граф пометил как internal.
  104.         // Алгоритм Дейкстры не оптимизировал. Оставил для следующей задачи.
  105.  
  106.         private static List<Node> Dijkstra(Graph graph, Dictionary<Edge, double> weights, Node start, Node end)
  107.         {
  108.             var notVisited = graph.Nodes.ToList();
  109.             var track = new Dictionary<Node, DijkstraData>();
  110.             track[start] = new DijkstraData {Price = 0, Previous = null};
  111.  
  112.             while (true)
  113.             {
  114.                 Node toOpen = null;
  115.                 var bestPrice = double.PositiveInfinity;
  116.                 foreach (var e in notVisited)
  117.                     if (track.ContainsKey(e) && track[e].Price < bestPrice)
  118.                     {
  119.                         bestPrice = track[e].Price;
  120.                         toOpen = e;
  121.                     }
  122.  
  123.                 if (toOpen == null) return null;
  124.                 if (toOpen == end) break;
  125.  
  126.                 foreach (var e in toOpen.IncidentEdges.Where(z => z.From == toOpen))
  127.                 {
  128.                     var currentPrice = track[toOpen].Price + weights[e];
  129.                     var nextNode = e.OtherNode(toOpen);
  130.                     if (!track.ContainsKey(nextNode) || track[nextNode].Price > currentPrice)
  131.                         track[nextNode] = new DijkstraData {Previous = toOpen, Price = currentPrice};
  132.                 }
  133.  
  134.                 notVisited.Remove(toOpen);
  135.             }
  136.  
  137.             var result = new List<Node>();
  138.             while (end != null)
  139.             {
  140.                 result.Add(end);
  141.                 end = track[end].Previous;
  142.             }
  143.             result.Reverse();
  144.             return result;
  145.         }
  146.     }
  147.  
  148.     internal class DijkstraData
  149.     {
  150.         public Node Previous { get; set; }
  151.         public double Price { get; set; }
  152.     }
  153.  
  154.     internal class Edge
  155.     {
  156.         public readonly Node From;
  157.         public readonly Node To;
  158.  
  159.         public Edge(Node first, Node second)
  160.         {
  161.             From = first;
  162.             To = second;
  163.         }
  164.  
  165.         public bool IsIncident(Node node)
  166.         {
  167.             return From == node || To == node;
  168.         }
  169.  
  170.         public Node OtherNode(Node node)
  171.         {
  172.             if (!IsIncident(node)) throw new ArgumentException();
  173.             if (From == node) return To;
  174.             return From;
  175.         }
  176.     }
  177.  
  178.     internal class Node
  179.     {
  180.         private readonly List<Edge> edges = new List<Edge>();
  181.         public readonly int NodeNumber;
  182.  
  183.         public Node(int number)
  184.         {
  185.             NodeNumber = number;
  186.         }
  187.  
  188.         public IEnumerable<Node> IncidentNodes
  189.         {
  190.             get { return edges.Select(z => z.OtherNode(this)); }
  191.         }
  192.  
  193.         public IEnumerable<Edge> IncidentEdges
  194.         {
  195.             get
  196.             {
  197.                 foreach (var e in edges) yield return e;
  198.             }
  199.         }
  200.  
  201.         public static Edge Connect(Node node1, Node node2, Graph graph)
  202.         {
  203.             if (!graph.Nodes.Contains(node1) || !graph.Nodes.Contains(node2)) throw new ArgumentException();
  204.             var edge = new Edge(node1, node2);
  205.             node1.edges.Add(edge);
  206.             return edge;
  207.         }
  208.     }
  209.  
  210.     internal class Graph
  211.     {
  212.         private readonly Node[] nodes;
  213.  
  214.         public Graph(int nodesCount)
  215.         {
  216.             nodes = Enumerable.Range(0, nodesCount).Select(z => new Node(z)).ToArray();
  217.         }
  218.  
  219.         public int Length => nodes.Length;
  220.  
  221.         public Node this[int index] => nodes[index];
  222.  
  223.         public IEnumerable<Node> Nodes
  224.         {
  225.             get
  226.             {
  227.                 foreach (var node in nodes) yield return node;
  228.             }
  229.         }
  230.  
  231.         public Edge Connect(int index1, int index2)
  232.         {
  233.             return Node.Connect(nodes[index1], nodes[index2], this);
  234.         }
  235.  
  236.         public IEnumerable<Edge> Edges
  237.         {
  238.             get { return nodes.SelectMany(z => z.IncidentEdges).Distinct(); }
  239.         }
  240.  
  241.         public static Graph MakeGraph(params int[] incidentNodes)
  242.         {
  243.             var graph = new Graph(incidentNodes.Max() + 1);
  244.             for (var i = 0; i < incidentNodes.Length - 1; i += 2)
  245.                 graph.Connect(incidentNodes[i], incidentNodes[i + 1]);
  246.             return graph;
  247.         }
  248.     }
  249. }
RAW Paste Data
Pastebin PRO WINTER Special!
Get 40% OFF Pastebin PRO accounts!
Top