using CzokoŚmieciarka.MonoGameView.DataModels.Enums; using CzokoŚmieciarka.MonoGameView.DataModels.Interfaces; using CzokoŚmieciarka.MonoGameView.DataModels.Interfaces.GarbageCollector; using CzokoŚmieciarka.MonoGameView.DataModels.Interfaces.TrashCans; using CzokoŚmieciarka.MonoGameView.DataModels.Models; using CzokoŚmieciarka.MonoGameView.DataModels.Models.Steps; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Xna.Framework.Content; using System.Threading; using CzokoŚmieciarka.MonoGameView.DataModels.GeneralModels.Models; using Microsoft.Xna.Framework.Graphics; using MonoGameView.DataModels.Models; namespace MonoGameView.Algorithms { public class BestFirstSearch { public GarbageCollector Collector { get; set; } public ICloneable[,] Grid { get; set; } public BestFirstSearch(GarbageCollector collector, ICloneable[,] grid) { this.Collector = collector; this.Grid = grid; } int count; public List Houses { get; set; } public List Dumps { get; set; } public Tuple,int,List> BestPath(ContentManager content, GarbageCollector collector, ICloneable[,] grid) { Houses = new List(); Dumps = new List(); for (int x = 0; x < grid.GetLength(0); x++) { for (int y = 0; y < grid.GetLength(1); y++) { if (grid[x, y] is House) { Houses.Add(new Coords(x, y)); } else if (grid[x,y] is Dump) { Dumps.Add(new Coords(x, y)); } } } var r = SearchBestFirst(content, collector, grid, 0); var dataToLog = Jazda(r.Item1, CopyGrid(grid), (GarbageCollector) collector.Clone()).ToList(); /*Oznaczenia *0 - trawa, nie do poruszania *10 - droga po której można się poruszać *11 - droga po której nie można się poruszać *20 - dom z którego można wziąć śmieci *21 - dom z którego nie można wziąć śmieci w tym momencie *22 - dom pusty, bez śmieci *30 - wysypisko szkła *31 - wysypisko plastików i metali *32 - wysypisko odpadów organicznych *33 - wysypisko papieru *40 - ruch w górę *41 - ruch w prawo *42 - ruch w dół *43 - ruch w lewo *50 - zbierz śmieci *51 - wyrzuć śmieci */ Console.WriteLine($"Counts : {count}"); using (StreamWriter writer = new StreamWriter("chuj.txt")) { foreach (var item in dataToLog) { string line = ""; if (item.Key is MoveStep) { MoveStep move = (item.Key as MoveStep); String[,] mygrid = item.Value; switch (move.GetDirection().ToString()) { case "Up": line += "40"; break; case "Right": line += "41"; break; case "Down": line += "42"; break; case "Left": line += "43"; break; } foreach (string field in mygrid) { switch (field) { case "grass": line += "," + "0"; break; case "road1": line += "," + "10"; break; case "road2": line += "," + "11"; break; case "house": line += "," + "20"; break; case "emptyHouse": line += "," + "22"; break; case "Glass": line += "," + "30"; break; case "PlasticMetal": line += "," + "31"; break; case "Organic": line += "," + "32"; break; case "Paper": line += "," + "33"; break; } } } else if (item.Key is CollectStep) { CollectStep collect = (item.Key as CollectStep); String[,] mygrid = item.Value; line += "50"; foreach (string field in mygrid) { switch (field) { case "grass": line += "," + "0"; break; case "road1": line += "," + "10"; break; case "road2": line += "," + "11"; break; case "house": line += "," + "20"; break; case "emptyHouse": line += "," + "22"; break; case "Glass": line += "," + "30"; break; case "PlasticMetal": line += "," + "31"; break; case "Organic": line += "," + "32"; break; case "Paper": line += "," + "33"; break; } } } else { SpillStep spill = (item.Key as SpillStep); String[,] mygrid = item.Value; line += "51"; foreach (string field in mygrid) { switch (field) { case "grass": line += "," + "0"; break; case "road1": line += "," + "10"; break; case "road2": line += "," + "11"; break; case "house": line += "," + "20"; break; case "emptyHouse": line += "," + "22"; break; case "Glass": line += "," + "30"; break; case "PlasticMetal": line += "," + "31"; break; case "Organic": line += "," + "32"; break; case "Paper": line += "," + "33"; break; } } } writer.WriteLine(line); } } if (r == null) return new Tuple, int, List>(new List(), 0, new List()); return r; } public IEnumerable> Jazda(List steps, ICloneable[,] grid, GarbageCollector collector) { for (int i =0;i= 0 && y >= 0 && x < grid.GetLength(0) && y < grid.GetLength(1)) { var cell = grid[x, y]; if (cell is Grass) minGrid[xoffset, yoffset] = "grass"; if (cell is Road1) minGrid[xoffset, yoffset] = "road1"; if (cell is Road2) minGrid[xoffset, yoffset] = "road2"; if (cell is Dump) minGrid[xoffset, yoffset] = (cell as Dump).TypeOfGarbage.GarbageType.ToString(); if (cell is House) minGrid[xoffset, yoffset] = "house"; if (cell is EmptyHouse) minGrid[xoffset, yoffset] = "emptyHouse"; } else { minGrid[xoffset, yoffset] = "grass"; } } } yield return new KeyValuePair(steps[i], minGrid); steps[i].Invoke(collector, grid); } } List PossibleSteps(AGarbageCollector collector, ICloneable[,] grid) { var result = new List(); var itemdupa = grid[collector.Coords.X, collector.Coords.Y]; if (grid[collector.Coords.X, collector.Coords.Y] is House) { var collectSteps = new List() { new CollectStep(GarbageType.Glass), new CollectStep(GarbageType.Organic), new CollectStep(GarbageType.Paper), new CollectStep(GarbageType.PlasticMetal) }; foreach (var item in collectSteps) { var copyCollector = (AGarbageCollector)collector.Clone(); var copyGrid = CopyGrid(grid); if (item.Invoke(copyCollector, copyGrid)) result.Add(item); } } if (grid[collector.Coords.X, collector.Coords.Y] is ADump) { var collectSteps = new List() { new SpillStep(GarbageType.Glass), new SpillStep(GarbageType.Organic), new SpillStep(GarbageType.Paper), new SpillStep(GarbageType.PlasticMetal) }; foreach (var item in collectSteps) { var copyCollector = (AGarbageCollector)collector.Clone(); var copyGrid = CopyGrid(grid); if (item.Invoke(copyCollector, copyGrid)) result.Add(item); } } if (!(grid[collector.Coords.X, collector.Coords.Y] is Dump && collector.TrashContainers.Any(x => x.FillPercent > 0 && (grid[collector.Coords.X, collector.Coords.Y] as Dump).TypeOfGarbage.GarbageType == x.TypeOfGarbage.GarbageType)) && !(grid[collector.Coords.X, collector.Coords.Y] is House && (grid[collector.Coords.X, collector.Coords.Y] as House).TrashCans.Any(j => j.FillPercent > 0 && collector.TrashContainers.Any(i => i.FillPercent < 1 && i.Garbage.TypeOfGarbage.GarbageType == j.TypeOfGarbage.GarbageType)))) { var moveSteps = new List() { new MoveStep(Direction.Up), new MoveStep(Direction.Down), new MoveStep(Direction.Left), new MoveStep(Direction.Right) }; var filteredMoveSteps = new List(); foreach (var item in moveSteps) { var copyCollector = (AGarbageCollector)collector.Clone(); if (item.Invoke(copyCollector, grid)) { var gcx = copyCollector.Coords.X; var gcy = copyCollector.Coords.Y; if (grid[gcx, gcy] is Road1 || grid[gcx, gcy] is House || (grid[gcx, gcy] is ADump && copyCollector.TrashContainers.Any(x => x.FillPercent > 0))) { result.Add(item); } } } } return result; } int Priority (Tuple,List>,GarbageCollector,ICloneable[,]> t) { var inHouses = Houses .Aggregate(0.0, (a, b) => a + (t.Item3[b.X, b.Y] as IGarbageLocalization) .TrashCans .Aggregate(0.0, (i, j) => i + j.Garbage.Weight)); var inDumps = Dumps .Aggregate(0.0, (a, b) => a + (t.Item3[b.X, b.Y] as ATrashCan).Garbage.Weight); var inCollector = t.Item2.TrashContainers.Aggregate(0.0, (a, b) => a + b.Garbage.Weight); double p1 = inCollector + 2*inHouses - 3*inDumps; var houses2 = Houses.Select(x => t.Item3[x.X, x.Y]).Where(x => x is House).Select(x => x as House).ToList(); var notFullCans = t.Item2.TrashContainers.Where(x => x.FillPercent != 1 && houses2.Any(i=> i.TrashCans.Any(j => j.TypeOfGarbage.GarbageType == x.TypeOfGarbage.GarbageType && j.FillPercent > 0)) ); if (!notFullCans.Any()) { var fullCans = t.Item2.TrashContainers.Where(x => x.FillPercent > 0); if (!fullCans.Any()) return 0; //var fullCan=fullCans.First(); var closestDump = Dumps .Select(x => t.Item3[x.X, x.Y]) .Select(i => i as Dump) .Where(i => fullCans.Any(j=>i.TypeOfGarbage.GarbageType == j.TypeOfGarbage.GarbageType)) .Min(b => Math.Pow(t.Item2.Coords.X - b.Coords.X, 2) + Math.Pow(t.Item2.Coords.Y - b.Coords.Y, 2)); return (int) (p1 * 1000 + closestDump); } else { //var notFullCan = notFullCans.First(); var closestHouses = Houses .Select(x => t.Item3[x.X, x.Y]) .Where(i => i is House) .Select(i => i as House) .Where(i => i.TrashCans.Any(x => notFullCans.Any(j=>x.TypeOfGarbage.GarbageType ==j.TypeOfGarbage.GarbageType && x.FillPercent > 0))); var closestHouse = (closestHouses.Any()) ? closestHouses.Min(b => Math.Pow(t.Item2.Coords.X - b.Coords.X, 2) + Math.Pow(t.Item2.Coords.Y - b.Coords.Y, 2)): 0.0; var closestDumps = Dumps .Select(x => t.Item3[x.X, x.Y]) .Select(i => i as Dump) .Where(i => notFullCans.Any(j=>i.TypeOfGarbage.GarbageType == j.TypeOfGarbage.GarbageType)); var closestDump = (closestDumps.Any()) ? closestDumps.Min(b => Math.Pow(t.Item2.Coords.X - b.Coords.X, 2) + Math.Pow(t.Item2.Coords.Y - b.Coords.Y, 2)) : 0.0; return (int) (p1 * 1000 + 100*closestHouse + closestDump); } } Tuple, int, List> SearchBestFirst(ContentManager content, GarbageCollector collector, ICloneable[,] grid, int length) { //Thread.Sleep(1); count = 0; var nodes = new PriorityQueue, List>, GarbageCollector, ICloneable[,]>>(); var f = new Tuple, List>, GarbageCollector, ICloneable[,]>(new KeyValuePair, List>(new List(),new List() { grid }), collector, grid); nodes.Enqueue(f,Priority(f)); while (true) { count++; var p = nodes.Dequeue(); var item = p.Key; var priority = p.Value; /*Thread.Sleep(10); this.Collector.Coords = item.Item2.Coords; this.Collector.TrashContainers = item.Item2.TrashContainers; for (int x = 0; x < item.Item3.GetLength(0); x++) { for (int y = 0; y < item.Item3.GetLength(1); y++) { this.Grid[x, y] = item.Item3[x, y]; } }*/ if (Houses.All(c => (item.Item3[c.X, c.Y] as IGarbageLocalization).TrashCans.All(j => j.FillPercent == 0.0)) && item.Item2.TrashContainers.All(i => i.FillPercent == 0.0) ) { return new Tuple, int, List>(item.Item1.Key, length, item.Item1.Value); } if (true)//item.Item2.Counter <= 12) { foreach (var step in PossibleSteps(item.Item2, item.Item3)) { if (step is SpillStep) { Console.WriteLine(); } var collectorClone = (GarbageCollector)item.Item2.Clone(); var gridClone = CopyGrid(item.Item3); step.Invoke(collectorClone, gridClone); var steps = new List(); steps.AddRange(item.Item1.Key); steps.Add(step); var f2 = new Tuple, List>, GarbageCollector, ICloneable[,]>(new KeyValuePair, List>(steps, item.Item1.Value.Concat(new List() {gridClone }).ToList()), collectorClone, gridClone); var f2P = Priority(f2); nodes.Enqueue(f2,Priority(f2)); } } } } private ICloneable[,] CopyGrid(ICloneable[,] grid) { ICloneable[,] result = new ICloneable[grid.GetLength(0), grid.GetLength(1)]; for (int x = 0; x < grid.GetLength(0); x++) { for (int y = 0; y < grid.GetLength(1); y++) { result[x, y] = (ICloneable)grid[x, y].Clone(); } } return result; } } }