/
Species.cs
234 lines (207 loc) · 7.18 KB
/
Species.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cas.Core.Interfaces;
namespace Cas.Core
{
public class Species : ISpecies
{
/// <summary>
/// Unique identifier for the species.
/// </summary>
public long Id {
get
{
return this.id;
}
}
private readonly long id;
private static long NextAvailableId = 1;
/// <summary>
/// An example of the agent that this species represents
/// </summary>
public IAgent Exemplar {
get
{
return this.exemplar;
}
}
private readonly IAgent exemplar;
/// <summary>
/// The generation that this species first arose.
/// </summary>
public long FirstSeen
{
get
{
return this.firstSeen;
}
}
private readonly long firstSeen;
/// <summary>
/// The species id(s) that this species arose from, if any.
/// </summary>
/// <remarks>
/// Species that were created at the start of the simulation
/// will have an empty list, species that arose from AsexualReproduction
/// will have one Id, and species that arose from SexualReproduction
/// will have two Ids.
/// </remarks>
public List<long> DerivedFromSpeciesIds
{
get
{
return this.derivedFromSpeciesIds;
}
}
private readonly List<long> derivedFromSpeciesIds = new List<long>();
/// <summary>
/// The number of resources consumed from ResourceNodes
/// across all agents in this species.
/// </summary>
public long ResourcesFromResourceNodes { get; private set; }
/// <summary>
/// The number of resources consumed from Agents
/// across all agents in this species.
/// </summary>
public long ResourcesFromAgents { get; private set; }
/// <summary>
/// A classifcation of this species based of what it consumes.
/// </summary>
/// <remarks>
/// 0-15% meat = herbivore
/// 16-85% meat = omnivore
/// 86-100% meat = carnivore
/// </remarks>
public DietType DietType
{
get
{
long totalConsumed = ResourcesFromAgents + ResourcesFromResourceNodes;
if (totalConsumed == 0) return DietType.None;
double percentMeat = (double)ResourcesFromAgents / (double)totalConsumed;
if (percentMeat < 0.15)
{
return DietType.Herbivore;
}
else if (percentMeat > 0.85)
{
return DietType.Carnivore;
}
return DietType.Omnivore;
}
}
private readonly ISimulation Simulation;
protected readonly Dictionary<long, long> preyCounts = new Dictionary<long, long>();
protected readonly Dictionary<long, long> predatorCounts = new Dictionary<long, long>();
public Species(ISimulation simulation, IAgent exemplar, params long[] derivedFromSpeciesIds)
{
if (simulation == null) throw new ArgumentNullException("simulation");
if (exemplar == null) throw new ArgumentNullException("exemplar");
this.Simulation = simulation;
this.firstSeen = simulation.CurrentGeneration;
this.id = NextAvailableId++;
this.ResourcesFromResourceNodes = 0;
this.ResourcesFromAgents = 0;
this.Population = 0;
this.derivedFromSpeciesIds.AddRange(derivedFromSpeciesIds);
this.exemplar = exemplar.DeepCopy();
}
/// <summary>
/// Report that an agent of this species consumed resources.
/// </summary>
public void RecordConsumptionOf(IIsUnique prey, int amount)
{
if (prey == null) throw new ArgumentNullException("prey");
if (amount < 1) throw new ArgumentOutOfRangeException("amount");
if (prey is ISpecies)
{
ResourcesFromAgents += amount;
(prey as ISpecies).RecordPredation(this);
}
else if (prey is Corpse)
{
ResourcesFromAgents += amount;
}
else // IResourceNode
{
ResourcesFromResourceNodes += amount;
}
// Increment the counter for this consumption
if (!preyCounts.ContainsKey(prey.Id))
{
preyCounts.Add(prey.Id, 0);
}
preyCounts[prey.Id] += 1;
}
/// <summary>
/// Report that an agent of this species was successfully attacked by a predator.
/// </summary>
public void RecordPredation(ISpecies predator)
{
// Increment the counter for this consumption
if (!predatorCounts.ContainsKey(predator.Id))
{
predatorCounts.Add(predator.Id, 0);
}
predatorCounts[predator.Id] += 1;
}
/// <summary>
/// The total number of agents in the simulation with this species.
/// </summary>
public long Population { get; set; }
/// <summary>
/// The locations in the simulation where at least one member of this species can be found.
/// </summary>
public IEnumerable<ILocation> Habitat
{
get
{
return this.Simulation
.Environment
.Locations
.Where(loc => loc.Agents.Any(agent => agent.Species == this));
}
}
/// <summary>
/// The foods that this species has consumed across all time, ordered by number of
/// occurences.
/// </summary>
public IEnumerable<IIsUnique> Prey
{
get
{
return this.preyCounts
.OrderByDescending(kvp => kvp.Value)
.Select(kvp =>
{
return (kvp.Key < 0) ?
this.Simulation.Environment.FindResourceNodeById(kvp.Key)
: this.Simulation.GetSpeciesOrFossil(kvp.Key);
});
}
}
/// <summary>
/// The agents that this species has been predated by across all time, ordered by number of
/// occurences.
/// </summary>
public IEnumerable<IIsUnique> Predators
{
get
{
return this.predatorCounts
.OrderByDescending(kvp => kvp.Value)
.Select(kvp => this.Simulation.GetSpeciesOrFossil(kvp.Key));
}
}
public string ToShortString()
{
return this.ToString();
}
public override string ToString()
{
return string.Format("S.{0}: {1}", this.id, this.exemplar.ToShortString());
}
}
}