-
Notifications
You must be signed in to change notification settings - Fork 3
/
ConflictAvoidanceTable.cs
188 lines (170 loc) · 7.14 KB
/
ConflictAvoidanceTable.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
using System.Collections.Generic;
using System.Linq;
namespace mapf
{
public class ConflictAvoidanceTable
{
Dictionary<TimedMove, List<int>> timedMovesToAgentNumList;
Dictionary<Move, (int time, int agentNum)> atGoalWaitsToTimeAndAgentNum; // No need for a list of agent nums because goals can't collide :)
public enum AvoidanceGoal
{
MINIMIZE_CONFLICTS,
MINIMIZE_CONFLICTING_GROUPS
};
public AvoidanceGoal avoidanceGoal = AvoidanceGoal.MINIMIZE_CONFLICTS;
public ConflictAvoidanceTable()
{
this.Clear();
}
public int GetMaxPlanSize()
{
if (atGoalWaitsToTimeAndAgentNum.Count > 0)
return atGoalWaitsToTimeAndAgentNum.Values.Max(tuple => tuple.time) - 1; // The first WAIT at goal we record is one time step after reaching it
else
return 0;
}
public void Clear()
{
timedMovesToAgentNumList = new Dictionary<TimedMove, List<int>>();
atGoalWaitsToTimeAndAgentNum = new Dictionary<Move, (int time, int agentNum)>();
NumPlans = 0;
}
public void AddPlan(SinglePlan plan)
{
int planSize = plan.GetSize();
for (int i = 0; i < planSize; i++)
{
Move temp = plan.GetLocationAt(i);
TimedMove step;
if (temp.GetType() == typeof(TimedMove))
step = (TimedMove)temp;
else // It's a Move object
{
queryTimedMove.setup(temp, i);
step = queryTimedMove;
}
if (this.timedMovesToAgentNumList.ContainsKey(step) == false)
{
if (ReferenceEquals(step, queryTimedMove)) // Need a separate object that would serve as the key
step = new TimedMove(step);
this.timedMovesToAgentNumList[step] = new List<int>() { plan.agentNum };
}
else
this.timedMovesToAgentNumList[step].Add(plan.agentNum);
}
Move lastMove = plan.GetLocationAt(planSize - 1);
var goal = new Move(lastMove.x, lastMove.y, Move.Direction.Wait);
this.atGoalWaitsToTimeAndAgentNum[goal] = (planSize, plan.agentNum);
++NumPlans;
}
public void RemovePlan(SinglePlan plan)
{
int planSize = plan.GetSize();
for (int i = 0; i < planSize; i++)
{
Move temp = plan.GetLocationAt(i);
TimedMove step;
if (temp.GetType() == typeof(TimedMove))
step = (TimedMove)temp;
else // It's a Move object
{
queryTimedMove.setup(temp, i);
step = queryTimedMove;
}
this.timedMovesToAgentNumList[step].Remove(plan.agentNum);
// TODO: Add asserts that check the plan was indeed in the CAT
}
Move lastMove = plan.GetLocationAt(planSize - 1);
queryMove.setup(lastMove.x, lastMove.y, Move.Direction.Wait);
this.atGoalWaitsToTimeAndAgentNum.Remove(queryMove);
--NumPlans;
}
/// <summary>
/// Gets the element that has the specified key in the read-only dictionary.
/// </summary>
/// <param name="key">The key to locate</param>
/// <returns>The element that has the specified key in the read-only dictionary</returns>
/// <exception cref="System.ArgumentNullException">key is null</exception>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">The property is retrieved and key is not found</exception>
public IReadOnlyList<int> this[TimedMove key]
{
get
{
List<int> ans = null;
if (this.timedMovesToAgentNumList.ContainsKey(key))
{
ans = new List<int>(this.timedMovesToAgentNumList[key].Count + 1);
ans.AddRange(this.timedMovesToAgentNumList[key]);
}
queryMove.setup(key);
if (this.atGoalWaitsToTimeAndAgentNum.ContainsKey(queryMove))
{
var timeAndAgentNum = this.atGoalWaitsToTimeAndAgentNum[queryMove];
if (key.time >= timeAndAgentNum.time)
{
if (ans == null)
ans = new List<int>() { timeAndAgentNum.agentNum };
else
ans.Add(timeAndAgentNum.agentNum);
}
}
if (ans != null)
return ans;
else
return ConflictAvoidanceTable.emptyList;
}
}
private static readonly List<int> emptyList = new List<int>(0);
private Move queryMove = new Move();
private TimedMove queryTimedMove = new TimedMove();
/// <summary>
/// Determines whether the read-only dictionary contains an element that has
/// the specified key.
/// </summary>
/// <param name="key">The key to locate.</param>
/// <returns>true if the read-only dictionary contains an element that has the specified key;
/// otherwise, false.</returns>
/// <exception cref="System.ArgumentNullException">key is null</exception>
public bool ContainsKey(TimedMove key)
{
if (this.timedMovesToAgentNumList.ContainsKey(key))
return true;
queryMove.setup(key);
if (this.atGoalWaitsToTimeAndAgentNum.ContainsKey(queryMove))
{
var timeAndAgentNum = this.atGoalWaitsToTimeAndAgentNum[queryMove];
if (key.time >= timeAndAgentNum.time)
return true;
}
return false;
}
/// <summary>
/// Gets the value that is associated with the specified key.
/// </summary>
/// <param name="key">The key to locate</param>
/// <param name="value">
/// When this method returns, the value associated with the specified key, if
/// the key is found; otherwise, the default value for the type of the value
/// parameter. This parameter is passed uninitialized.
/// </param>
/// <exception cref="System.ArgumentNullException">key is null</exception>
/// <returns>
/// true if the object that implements the System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>
/// interface contains an element that has the specified key; otherwise, false.
/// </returns>
public bool TryGetValue(TimedMove key, out IReadOnlyList<int> value)
{
if (this.ContainsKey(key))
{
value = this[key];
return true;
}
else
{
value = null;
return false;
}
}
public int NumPlans { get; private set; }
}
}