forked from tylercamp/palcalc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBreedingDistanceMap.cs
87 lines (73 loc) · 3.41 KB
/
BreedingDistanceMap.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
using PalCalc.Model;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PalCalc.GenDB
{
internal class BreedingDistanceMap
{
private static ILogger logger = Log.ForContext<BreedingDistanceMap>();
// min. number of times you need to breed Key1 to get a Key2 (to prune out path checks between pals which would exceed the max breeding steps)
public static Dictionary<Pal, Dictionary<Pal, int>> CalcMinDistances(PalDB db, PalBreedingDB breedingdb)
{
Logging.InitCommonFull();
Dictionary<Pal, Dictionary<Pal, int>> palDistances = new Dictionary<Pal, Dictionary<Pal, int>>();
foreach (var p in db.Pals)
palDistances.Add(p, new Dictionary<Pal, int>() { { p, 0 } });
List<(Pal, Pal)> toCheck = new List<(Pal, Pal)>(db.Pals.SelectMany(p => db.Pals.Where(i => i != p).Select(p2 => (p, p2))));
bool didUpdate = true;
while (didUpdate)
{
didUpdate = false;
List<(Pal, Pal)> resolved = new List<(Pal, Pal)>();
List<(Pal, Pal)> unresolved = new List<(Pal, Pal)>();
foreach (var next in toCheck)
{
var src = next.Item1;
var target = next.Item2;
// check if there's a direct way to breed from src to target
if (breedingdb.BreedingByChild[target].Any(kvp => kvp.Key.Pal == src))
{
if (!palDistances[src].ContainsKey(target) || palDistances[src][target] != 1)
{
didUpdate = true;
palDistances[src][target] = 1;
resolved.Add(next);
}
continue;
}
// check if there's a possible child of this `src` with known distance to target
var childWithShortestDistance = breedingdb.BreedingByParent[src].Values
.SelectMany(l => l.Select(b => b.Child))
.Where(child => palDistances[child].ContainsKey(target))
.OrderBy(child => palDistances[child][target])
.FirstOrDefault();
if (childWithShortestDistance != null)
{
if (!palDistances[src].ContainsKey(target) || palDistances[src][target] != palDistances[childWithShortestDistance][target] + 1)
{
didUpdate = true;
palDistances[src][target] = palDistances[childWithShortestDistance][target] + 1;
resolved.Add(next);
}
continue;
}
unresolved.Add(next);
}
logger.Information("Resolved {0} entries with {1} left unresolved", resolved.Count, unresolved.Count);
if (!didUpdate)
{
// the remaining (src,target) pairs are impossible
foreach (var p in unresolved)
{
palDistances[p.Item1].Add(p.Item2, 10000);
}
}
}
return palDistances;
}
}
}