Czoko_Smieciarka/Trunk/MonoGameView/Algorithms/BestFirstSearch.cs
2019-06-11 23:17:44 +02:00

380 lines
14 KiB
C#

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.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Content;
using System.Threading;
using CzokoŚmieciarka.MonoGameView.DataModels.GeneralModels.Models;
using MonoGameView.DataModels.Models;
using System.IO;
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<Coords> Houses { get; set; }
public List<Coords> Dumps { get; set; }
public Tuple<List<IStep>,int,List<ICloneable[,]>> BestPath(ContentManager content, GarbageCollector collector, ICloneable[,] grid)
{
Houses = new List<Coords>();
Dumps = new List<Coords>();
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);
Jazda(r.Item1, CopyGrid(grid), (GarbageCollector) collector.Clone());
Console.WriteLine($"Counts : {count}");
if (r == null) return new Tuple<List<IStep>, int, List<ICloneable[,]>>(new List<IStep>(), 0, new List<ICloneable[,]>());
return r;
}
public void Jazda(List<IStep> steps, ICloneable[,] grid, GarbageCollector collector)
{
for (int i =0;i<steps.Count();i++)
{
var s = "";
foreach (var can in collector.TrashContainers)
{
s += " " + can.TypeOfGarbage.GarbageType.ToString() + ":." + (int)can.FillPercent * 100;
}
for (int x = collector.Coords.X - 2; x <= collector.Coords.X + 2; x++)
{
for (int y = collector.Coords.Y - 2; y <= collector.Coords.Y + 2; y++)
{
var xoffset = x - (collector.Coords.X - 2);
var yoffset = y - (collector.Coords.Y - 2);
if (x >= 0 && y >= 0 && x < grid.GetLength(0) && y < grid.GetLength(1))
{
var cell = grid[x, y];
if (cell is Grass) s += " " + xoffset.ToString() + yoffset.ToString() + "grass";
if (cell is Road1) s += " " + xoffset.ToString() + yoffset.ToString() + "road1";
if (cell is Road2) s += " " + xoffset.ToString() + yoffset.ToString() + "road2";
if (cell is Dump) s += " " + xoffset.ToString() + yoffset.ToString() + (cell as Dump).TypeOfGarbage.GarbageType.ToString();
if (cell is House)
{
var h = (cell as House);
foreach (var can in h.TrashCans)
{
s += " " + xoffset.ToString() + yoffset.ToString() + can.TypeOfGarbage.GarbageType.ToString() + ":." + (int)can.FillPercent * 100;
}
}
if (cell is EmptyHouse) s += " " + xoffset.ToString() + yoffset.ToString() + "emptyHouse";
}
else
{
s += " " + xoffset.ToString() + yoffset.ToString() + "grass";
}
}
}
for (int l = 0; l < 12; l++)
{
var minGrid = new ICloneable[5, 5];
var s0 = ((steps[i].ID == l) ? 1 : 0) + " |";
using (StreamWriter w = File.AppendText("garbage_dataset" + l + ".txt"))
{
w.WriteLine(s0 + s);
}
}
steps[i].Invoke(collector, grid);
}
}
List<IStep> PossibleSteps(AGarbageCollector collector, ICloneable[,] grid)
{
var result = new List<IStep>();
var itemdupa = grid[collector.Coords.X, collector.Coords.Y];
if (grid[collector.Coords.X, collector.Coords.Y] is House)
{
var collectSteps = new List<IStep>()
{
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<IStep>()
{
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<IStep>()
{
new MoveStep(Direction.Up),
new MoveStep(Direction.Down),
new MoveStep(Direction.Left),
new MoveStep(Direction.Right)
};
var filteredMoveSteps = new List<IStep>();
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<KeyValuePair<List<IStep>,List<ICloneable[,]>>,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<List<IStep>, int, List<ICloneable[,]>> SearchBestFirst(ContentManager content, GarbageCollector collector, ICloneable[,] grid, int length)
{
//Thread.Sleep(1);
count = 0;
var nodes = new PriorityQueue<Tuple<KeyValuePair<List<IStep>, List<ICloneable[,]>>, GarbageCollector, ICloneable[,]>>();
var f = new Tuple<KeyValuePair<List<IStep>, List<ICloneable[,]>>, GarbageCollector, ICloneable[,]>(new KeyValuePair<List<IStep>, List<ICloneable[,]>>(new List<IStep>(),new List<ICloneable[,]>() { 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 || j.FillPercent == double.NaN))
&&
item.Item2.TrashContainers.All(i => i.FillPercent == 0.0)
)
{
return new Tuple<List<IStep>, int, List<ICloneable[,]>>(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<IStep>();
steps.AddRange(item.Item1.Key);
steps.Add(step);
var f2 = new Tuple<KeyValuePair<List<IStep>, List<ICloneable[,]>>, GarbageCollector, ICloneable[,]>(new KeyValuePair<List<IStep>, List<ICloneable[,]>>(steps, item.Item1.Value.Concat(new List<ICloneable[,]>() {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;
}
}
}