-
Notifications
You must be signed in to change notification settings - Fork 5
/
PalPropertyGrouping.cs
106 lines (88 loc) · 4.1 KB
/
PalPropertyGrouping.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using PalCalc.Model;
using PalCalc.Solver.PalReference;
using PalCalc.Solver.ResultPruning;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PalCalc.Solver
{
public static class PalProperty
{
public delegate int GroupIdFn(IPalReference p);
public static GroupIdFn Pal = p => p.Pal.Id.GetHashCode();
public static GroupIdFn Gender = p => (int)p.Gender;
public static GroupIdFn WildPalCount = p => p.NumWildPalParticipants();
public static GroupIdFn NumBreedingSteps = p => p.NumTotalBreedingSteps;
public static GroupIdFn EffectivePassives = p => p.EffectivePassivesHash;
public static GroupIdFn ActualPassives = p => p.ActualPassives.SetHash();
public static GroupIdFn TotalEffort = p => p.BreedingEffort.GetHashCode();
public static GroupIdFn LocationType = p => p.Location.GetType().GetHashCode();
/// <summary>
/// Makes a grouping function based on the result of applying `mainFn` to all
/// elements (i.e. children and self) of a provided pal reference.
/// </summary>
public static GroupIdFn Recursive(GroupIdFn mainFn) => p =>
p.AllReferences().Select(i => mainFn(i)).SetHash();
public static GroupIdFn RecursiveWhere(GroupIdFn mainFn, Func<IPalReference, bool> filter) => p =>
p.AllReferences().Where(filter).Select(i => mainFn(i)).SetHash();
/// <summary>
/// Makes a grouping function as a combination of the provided functions.
/// </summary>
public static GroupIdFn Combine(params GroupIdFn[] fns) => p =>
{
int groupId = 0;
foreach (var fn in fns) groupId = HashCode.Combine(groupId, fn(p));
return groupId;
};
}
public class PalPropertyGrouping(PalProperty.GroupIdFn groupIdFn)
{
private Dictionary<int, List<IPalReference>> content = new Dictionary<int, List<IPalReference>>();
public void Add(IPalReference p)
{
var groupId = groupIdFn(p);
var group = content.GetValueOrElse(groupId, new List<IPalReference>());
content.TryAdd(groupId, group);
if (!group.Contains(p)) group.Add(p);
}
public void AddRange(IEnumerable<IPalReference> items)
{
foreach (var i in items) Add(i);
}
public void Remove(IPalReference p) => content.GetValueOrDefault(groupIdFn(p))?.Remove(p);
public IReadOnlyList<IPalReference> this[IPalReference r] => content.GetValueOrDefault(groupIdFn(r));
public IReadOnlyList<IPalReference> this[int groupId] => content.GetValueOrDefault(groupId);
public IEnumerable<IPalReference> All => content.SelectMany(kvp => kvp.Value);
public int TotalCount => content.Sum(kvp => kvp.Value.Count);
public delegate IEnumerable<IPalReference> FilterFunc(IEnumerable<IPalReference> input);
public void FilterAll(FilterFunc filterFn)
{
foreach (var group in content.Keys)
content[group] = filterFn(content[group]).ToList();
}
public void FilterAll(PruningRulesBuilder prb, CancellationToken token)
{
var pruner = prb.BuildAggregate(token);
foreach (var group in content.Keys.TakeWhile(_ => !token.IsCancellationRequested))
content[group] = pruner.Apply(content[group]).ToList();
}
public void Filter(int key, FilterFunc filterFn)
{
var group = content.GetValueOrDefault(key);
if (group == null) return;
var toKeep = filterFn(group);
group.RemoveAll(r => !toKeep.Contains(r));
content[key] = filterFn(group).ToList();
}
public void Filter(IPalReference key, FilterFunc filterFn) => Filter(groupIdFn(key), filterFn);
public PalPropertyGrouping BuildNew(PalProperty.GroupIdFn newIdFn)
{
var res = new PalPropertyGrouping(newIdFn);
foreach (var r in All)
res.Add(r);
return res;
}
}
}