inz-00/Assets/Map/LocationGenerator.cs
2019-08-17 14:08:41 +02:00

98 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Voronoi;
using Random = System.Random;
namespace Assets.Map
{
public class LocationGenerator
{
private readonly Graph<LocationSite> _sites;
private readonly Graph<Location> _locations;
private readonly List<(int, Location)> _queue = new List<(int, Location)>();
private readonly Dictionary<Location, List<int>> _blacklist = new Dictionary<Location, List<int>>();
private readonly Random _random;
public Graph<LocationSite> Sites => _sites;
public Graph<Location> Result => _locations;
public bool Done => _queue.Count == 0;
public LocationGenerator(List<Location> locations, Graph<Site> sites, Random random = null)
{
_sites = sites.Morph(s => new LocationSite(s));
_locations = new Graph<Location> { Vertices = new List<Location>(locations) };
_random = random ?? new Random();
}
public void SetLocation(int vertex, Location location)
{
_sites.Vertices[vertex].Location = location;
location.Sites.Add(_sites.Vertices[vertex]);
FixBoundaryPoints(vertex, location);
FixBoundaryEdges(vertex, location);
foreach (var neighbour in _sites.Neighbours(vertex))
if (_sites.Vertices[neighbour].Location == null)
_queue.Add((neighbour, location));
else if (location != _sites.Vertices[neighbour].Location)
_locations.AddEdge(
_locations.Vertices.IndexOf(location),
_locations.Vertices.IndexOf(_sites.Vertices[neighbour].Location)
);
}
private (int, Location) Dequeue()
{
while (_queue.Count > 0)
{
var index = _random.Next(_queue.Count);
var pair = _queue[index];
_queue.RemoveAt(index);
if (_sites.Vertices[pair.Item1].Location == null) return pair;
}
throw new Exception("No more elements.");
}
public void Step()
{
try
{
var (vertex, location) = Dequeue();
SetLocation(vertex, location);
}
catch (Exception ex)
{
}
}
private void FixBoundaryPoints(int vertex, Location location)
{
var a = location.BoundaryPoints;
var b = _sites.Vertices[vertex].Site.Vertices;
if (!_blacklist.ContainsKey(location)) _blacklist[location] = new List<int>();
_blacklist[location].AddRange(a.Intersect(b));
location.BoundaryPoints = a.Union(b).Except(_blacklist[location]).ToList();
}
private void FixBoundaryEdges(int vertex, Location location)
{
var a = location.BoundaryEdges;
var b = _sites.Vertices[vertex].Site.Edges;
location.BoundaryEdges = a.Union(b).Except(a.Intersect(b)).ToList();
}
}
}