574 lines
20 KiB
C#
574 lines
20 KiB
C#
using AntMe.Deutsch;
|
|
using System;
|
|
using System.CodeDom;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using AntMe.Simulation;
|
|
|
|
namespace AntMe.Player.BrainArmyAnts
|
|
{
|
|
/// <summary>
|
|
/// Diese Datei enthält die Beschreibung für deine Ameise. Die einzelnen Code-Blöcke
|
|
/// (Beginnend mit "public override void") fassen zusammen, wie deine Ameise in den
|
|
/// entsprechenden Situationen reagieren soll. Welche Befehle du hier verwenden kannst,
|
|
/// findest du auf der Befehlsübersicht im Wiki (http://wiki.antme.net/de/API1:Befehlsliste).
|
|
///
|
|
/// Wenn du etwas Unterstützung bei der Erstellung einer Ameise brauchst, findest du
|
|
/// in den AntMe!-Lektionen ein paar Schritt-für-Schritt Anleitungen.
|
|
/// (http://wiki.antme.net/de/Lektionen)
|
|
/// </summary>
|
|
[Spieler(
|
|
Volkname = "BrainArmyAnts", // Hier kannst du den Namen des Volkes festlegen
|
|
Vorname = "Joshua Priebsch,", // An dieser Stelle kannst du dich als Schöpfer der Ameise eintragen
|
|
Nachname = "Sebastian Seedorf" // An dieser Stelle kannst du dich als Schöpfer der Ameise eintragen
|
|
)]
|
|
|
|
/// Kasten stellen "Berufsgruppen" innerhalb deines Ameisenvolkes dar. Du kannst hier mit
|
|
/// den Fähigkeiten einzelner Ameisen arbeiten. Wie genau das funktioniert kannst du der
|
|
/// Lektion zur Spezialisierung von Ameisen entnehmen (http://wiki.antme.net/de/Lektion7).
|
|
[Kaste(
|
|
Name = "Sammler", // Name der Berufsgruppe
|
|
AngriffModifikator = -1, // Angriffsstärke einer Ameise
|
|
DrehgeschwindigkeitModifikator = -1, // Drehgeschwindigkeit einer Ameise
|
|
EnergieModifikator = -1, // Lebensenergie einer Ameise
|
|
GeschwindigkeitModifikator = 2, // Laufgeschwindigkeit einer Ameise
|
|
LastModifikator = 2, // Tragkraft einer Ameise
|
|
ReichweiteModifikator = -1, // Ausdauer einer Ameise
|
|
SichtweiteModifikator = 0 // Sichtweite einer Ameise
|
|
),
|
|
Kaste(
|
|
Name = "Erkunder", // Name der Berufsgruppe
|
|
AngriffModifikator = -1, // Angriffsstärke einer Ameise
|
|
DrehgeschwindigkeitModifikator = -1, // Drehgeschwindigkeit einer Ameise
|
|
EnergieModifikator = -1, // Lebensenergie einer Ameise
|
|
GeschwindigkeitModifikator = 1, // Laufgeschwindigkeit einer Ameise
|
|
LastModifikator = -1, // Tragkraft einer Ameise
|
|
ReichweiteModifikator = 1, // Ausdauer einer Ameise
|
|
SichtweiteModifikator = 2 // Sichtweite einer Ameise
|
|
),
|
|
Kaste(
|
|
Name = "Krieger", // Name der Berufsgruppe
|
|
AngriffModifikator = 2, // Angriffsstärke einer Ameise
|
|
DrehgeschwindigkeitModifikator = 0, // Drehgeschwindigkeit einer Ameise
|
|
EnergieModifikator = 1, // Lebensenergie einer Ameise
|
|
GeschwindigkeitModifikator = 0, // Laufgeschwindigkeit einer Ameise
|
|
LastModifikator = -1, // Tragkraft einer Ameise
|
|
ReichweiteModifikator = -1, // Ausdauer einer Ameise
|
|
SichtweiteModifikator = -1 // Sichtweite einer Ameise
|
|
)]
|
|
|
|
public class BrainArmyAntsKlasse : Basisameise
|
|
{
|
|
private static Bau bau = null;
|
|
private static readonly Random rand = new Random();
|
|
private static readonly List<Zucker> VorkZuckers = new List<Zucker>();
|
|
private static readonly List<int> RemovedZuckers = new List<int>();
|
|
private static readonly List<ObstTraeger> VorkObsts = new List<ObstTraeger>();
|
|
private static readonly List<Insekt> VorkFeinde = new List<Insekt>();
|
|
private static int GestorbeneAmeisen = 0;
|
|
private static int GetoeteteAmeisen = 0;
|
|
|
|
private Spielobjekt _z;
|
|
private Insekt _aktuellerFeind;
|
|
|
|
#region Kasten
|
|
|
|
/// <summary>
|
|
/// Jedes mal, wenn eine neue Ameise geboren wird, muss ihre Berufsgruppe
|
|
/// bestimmt werden. Das kannst du mit Hilfe dieses Rückgabewertes dieser
|
|
/// Methode steuern.
|
|
/// Weitere Infos unter http://wiki.antme.net/de/API1:BestimmeKaste
|
|
/// </summary>
|
|
/// <param name="anzahl">Anzahl Ameisen pro Kaste</param>
|
|
/// <returns>Name der Kaste zu der die geborene Ameise gehören soll</returns>
|
|
public override string BestimmeKaste(Dictionary<string, int> anzahl)
|
|
{
|
|
int count = 0;
|
|
foreach(KeyValuePair<string, int> entry in anzahl)
|
|
{
|
|
count += entry.Value;
|
|
}
|
|
if (anzahl["Krieger"] < 6 || anzahl["Sammler"] > anzahl["Krieger"] * (GetoeteteAmeisen/(GestorbeneAmeisen+1)))
|
|
return "Krieger";
|
|
if (anzahl["Sammler"] > anzahl["Erkunder"] * 20)
|
|
return "Erkunder";
|
|
|
|
|
|
// Gibt den Namen der betroffenen Kaste zurück.
|
|
return "Sammler";
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Fortbewegung
|
|
|
|
/// <summary>
|
|
/// Wenn die Ameise keinerlei Aufträge hat, wartet sie auf neue Aufgaben. Um dir das
|
|
/// mitzuteilen, wird diese Methode hier aufgerufen.
|
|
/// Weitere Infos unter http://wiki.antme.net/de/API1:Wartet
|
|
/// </summary>
|
|
public override void Wartet()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Erreicht eine Ameise ein drittel ihrer Laufreichweite, wird diese Methode aufgerufen.
|
|
/// Weitere Infos unter http://wiki.antme.net/de/API1:WirdM%C3%BCde
|
|
/// </summary>
|
|
public override void WirdMüde()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Wenn eine Ameise stirbt, wird diese Methode aufgerufen. Man erfährt dadurch, wie
|
|
/// die Ameise gestorben ist. Die Ameise kann zu diesem Zeitpunkt aber keinerlei Aktion
|
|
/// mehr ausführen.
|
|
/// Weitere Infos unter http://wiki.antme.net/de/API1:IstGestorben
|
|
/// </summary>
|
|
/// <param name="todesart">Art des Todes</param>
|
|
public override void IstGestorben(Todesart todesart)
|
|
{
|
|
foreach (ObstTraeger obstTraeger in VorkObsts)
|
|
{
|
|
obstTraeger.AmeiseEntfernen(this);
|
|
}
|
|
if (todesart == Todesart.Besiegt)
|
|
{
|
|
GestorbeneAmeisen++;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Diese Methode wird in jeder Simulationsrunde aufgerufen - ungeachtet von zusätzlichen
|
|
/// Bedingungen. Dies eignet sich für Aktionen, die unter Bedingungen ausgeführt werden
|
|
/// sollen, die von den anderen Methoden nicht behandelt werden.
|
|
/// Weitere Infos unter http://wiki.antme.net/de/API1:Tick
|
|
/// </summary>
|
|
public override void Tick()
|
|
{
|
|
if (ZurückgelegteStrecke*2+2 > Reichweite)
|
|
{
|
|
SchrittBau();
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if (Kaste == "Sammler")
|
|
{
|
|
if (AktuelleLast > 0)
|
|
{
|
|
SchrittBau();
|
|
}
|
|
else
|
|
{
|
|
_z = BestimmeZiel();
|
|
if (_z == null)
|
|
{
|
|
GeheGeradeaus(10);
|
|
if (rand.Next(50) == 0)
|
|
DreheUmWinkel(60);
|
|
}
|
|
else
|
|
{
|
|
SchrittZiel(_z);
|
|
}
|
|
}
|
|
} else if (Kaste == "Krieger")
|
|
{
|
|
//SprüheMarkierung(5, 10);
|
|
_z = BestimmeZiel();
|
|
if (_z == null)
|
|
{
|
|
GeheGeradeaus(10);
|
|
if (rand.Next(50) == 0)
|
|
DreheUmWinkel(60);
|
|
}
|
|
else
|
|
{
|
|
SchrittZiel(_z);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GeheGeradeaus();
|
|
//SprüheMarkierung(4, 30);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nahrung
|
|
|
|
/// <summary>
|
|
/// Sobald eine Ameise innerhalb ihres Sichtradius einen Apfel erspäht wird
|
|
/// diese Methode aufgerufen. Als Parameter kommt das betroffene Stück Obst.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:Sieht(Obst)"
|
|
/// </summary>
|
|
/// <param name="obst">Das gesichtete Stück Obst</param>
|
|
public override void Sieht(Obst obst)
|
|
{
|
|
ObstHinzufügen(obst);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sobald eine Ameise innerhalb ihres Sichtradius einen Zuckerhügel erspäht wird
|
|
/// diese Methode aufgerufen. Als Parameter kommt der betroffene Zuckerghügel.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:Sieht(Zucker)"
|
|
/// </summary>
|
|
/// <param name="zucker">Der gesichtete Zuckerhügel</param>
|
|
public override void Sieht(Zucker zucker)
|
|
{
|
|
ZuckerHinzufügen(zucker);
|
|
ZuckerEntfernen();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hat die Ameise ein Stück Obst als Ziel festgelegt, wird diese Methode aufgerufen,
|
|
/// sobald die Ameise ihr Ziel erreicht hat. Ab jetzt ist die Ameise nahe genug um mit
|
|
/// dem Ziel zu interagieren.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:ZielErreicht(Obst)"
|
|
/// </summary>
|
|
/// <param name="obst">Das erreichte Stück Obst</param>
|
|
public override void ZielErreicht(Obst obst)
|
|
{
|
|
if (Kaste == "Sammler")
|
|
{
|
|
Nimm(obst);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hat die Ameise eine Zuckerhügel als Ziel festgelegt, wird diese Methode aufgerufen,
|
|
/// sobald die Ameise ihr Ziel erreicht hat. Ab jetzt ist die Ameise nahe genug um mit
|
|
/// dem Ziel zu interagieren.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:ZielErreicht(Zucker)"
|
|
/// </summary>
|
|
/// <param name="zucker">Der erreichte Zuckerhügel</param>
|
|
public override void ZielErreicht(Zucker zucker)
|
|
{
|
|
if (Kaste == "Sammler")
|
|
{
|
|
Nimm(zucker);
|
|
ZuckerEntfernen();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Kommunikation
|
|
|
|
/// <summary>
|
|
/// Markierungen, die von anderen Ameisen platziert werden, können von befreundeten Ameisen
|
|
/// gewittert werden. Diese Methode wird aufgerufen, wenn eine Ameise zum ersten Mal eine
|
|
/// befreundete Markierung riecht.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:RiechtFreund(Markierung)"
|
|
/// </summary>
|
|
/// <param name="markierung">Die gerochene Markierung</param>
|
|
public override void RiechtFreund(Markierung markierung)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch
|
|
/// andere Spielelemente. Entdeckt die Ameise eine Ameise aus dem eigenen Volk, so
|
|
/// wird diese Methode aufgerufen.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtFreund(Ameise)"
|
|
/// </summary>
|
|
/// <param name="ameise">Erspähte befreundete Ameise</param>
|
|
public override void SiehtFreund(Ameise ameise)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch
|
|
/// andere Spielelemente. Entdeckt die Ameise eine Ameise aus einem befreundeten Volk
|
|
/// (Völker im selben Team), so wird diese Methode aufgerufen.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtVerb%C3%BCndeten(Ameise)"
|
|
/// </summary>
|
|
/// <param name="ameise">Erspähte verbündete Ameise</param>
|
|
public override void SiehtVerbündeten(Ameise ameise)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Kampf
|
|
|
|
/// <summary>
|
|
/// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch
|
|
/// andere Spielelemente. Entdeckt die Ameise eine Ameise aus einem feindlichen Volk,
|
|
/// so wird diese Methode aufgerufen.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtFeind(Ameise)"
|
|
/// </summary>
|
|
/// <param name="ameise">Erspähte feindliche Ameise</param>
|
|
public override void SiehtFeind(Ameise ameise)
|
|
{
|
|
/*if (Kaste == "Sammler")
|
|
{
|
|
*/FeindHinzufügen(ameise);/*
|
|
}
|
|
else */if (Kaste == "Krieger" && Koordinate.BestimmeEntfernung(this, ameise) < 4)
|
|
{
|
|
GreifeAn(ameise);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch
|
|
/// andere Spielelemente. Entdeckt die Ameise eine Wanze, so wird diese Methode aufgerufen.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtFeind(Wanze)"
|
|
/// </summary>
|
|
/// <param name="wanze">Erspähte Wanze</param>
|
|
public override void SiehtFeind(Wanze wanze)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Es kann vorkommen, dass feindliche Lebewesen eine Ameise aktiv angreifen. Sollte
|
|
/// eine feindliche Ameise angreifen, wird diese Methode hier aufgerufen und die
|
|
/// Ameise kann entscheiden, wie sie darauf reagieren möchte.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:WirdAngegriffen(Ameise)"
|
|
/// </summary>
|
|
/// <param name="ameise">Angreifende Ameise</param>
|
|
public override void WirdAngegriffen(Ameise ameise)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Es kann vorkommen, dass feindliche Lebewesen eine Ameise aktiv angreifen. Sollte
|
|
/// eine Wanze angreifen, wird diese Methode hier aufgerufen und die Ameise kann
|
|
/// entscheiden, wie sie darauf reagieren möchte.
|
|
/// Weitere Infos unter "http://wiki.antme.net/de/API1:WirdAngegriffen(Wanze)"
|
|
/// </summary>
|
|
/// <param name="wanze">Angreifende Wanze</param>
|
|
public override void WirdAngegriffen(Wanze wanze)
|
|
{
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Eigene
|
|
|
|
private Spielobjekt BestimmeZiel()
|
|
{
|
|
ZuckerEntfernen();
|
|
ObstEntfernen();
|
|
FeindEntfernen();
|
|
var entfernung = int.MaxValue;
|
|
|
|
|
|
Spielobjekt s = null;
|
|
|
|
if (Kaste == "Sammler")
|
|
{
|
|
foreach (ObstTraeger obstTraeger in VorkObsts)
|
|
{
|
|
if (obstTraeger.IstTraeger(this)) return obstTraeger.Obst;
|
|
}
|
|
foreach (var obst in VorkObsts)
|
|
{
|
|
var neu = Koordinate.BestimmeEntfernung(this, obst.Obst);
|
|
if (s != null && neu >= entfernung || neu >= Reichweite / 3 || !obst.BrauchtNochTraeger())
|
|
continue; //Ich verstehe das "z != null &&" nicht
|
|
s = obst.Obst;
|
|
entfernung = neu;
|
|
}
|
|
|
|
foreach (var zucker in VorkZuckers)
|
|
{
|
|
var neu = Koordinate.BestimmeEntfernung(this, zucker);
|
|
if (s != null && neu >= entfernung || neu >= Reichweite / 3)
|
|
continue;
|
|
s = zucker;
|
|
entfernung = neu;
|
|
}
|
|
|
|
if (s is Obst)
|
|
{
|
|
VorkObsts.Find(o => o.Obst == s).AmeiseHinzufügen(this);
|
|
}
|
|
}
|
|
else if(Kaste == "Krieger")
|
|
{
|
|
if (_aktuellerFeind != null)
|
|
{
|
|
var neu = Koordinate.BestimmeEntfernung(this, _aktuellerFeind);
|
|
if (!(neu >= Reichweite / 3 && (Angriff == 0 || _aktuellerFeind.Angriff > 0 &&
|
|
_aktuellerFeind.AktuelleEnergie / Angriff <
|
|
AktuelleEnergie / _aktuellerFeind.Angriff)))
|
|
return s;
|
|
}
|
|
foreach (var feind in VorkFeinde)
|
|
{
|
|
var neu = Koordinate.BestimmeEntfernung(this, feind);
|
|
if (s != null && neu >= entfernung || neu >= Reichweite / 3)
|
|
continue;
|
|
if (Angriff==0 || feind.Angriff>0 && feind.AktuelleEnergie/Angriff < AktuelleEnergie/feind.Angriff)
|
|
continue;
|
|
if (rand.Next(6)<1)
|
|
s = feind;
|
|
entfernung = neu;
|
|
}
|
|
_aktuellerFeind = (Insekt) s;
|
|
}
|
|
return s;
|
|
|
|
}
|
|
|
|
private void SchrittZiel(Spielobjekt ziel)
|
|
{
|
|
var dist = Koordinate.BestimmeEntfernung(this, ziel);
|
|
var angle = Koordinate.BestimmeRichtung(this, ziel);
|
|
if (Math.Abs(angle-Richtung) > 10)
|
|
DreheInRichtung(angle);
|
|
DreheZuZiel(ziel);
|
|
if (dist > 2)
|
|
GeheGeradeaus(dist/3*2);
|
|
else
|
|
GeheZuZiel(ziel);
|
|
}
|
|
|
|
private void SchrittBau()
|
|
{
|
|
if (bau == null)
|
|
{
|
|
GeheZuBau();
|
|
bau = (Bau) Ziel;
|
|
BleibStehen();
|
|
}
|
|
var dist = Koordinate.BestimmeEntfernung(this, bau);
|
|
var angle = Koordinate.BestimmeRichtung(this, bau);
|
|
if (Math.Abs(angle-Richtung) > 10)
|
|
DreheInRichtung(angle);
|
|
if (dist > 4)
|
|
GeheGeradeaus(dist-2);
|
|
else
|
|
GeheZuZiel(bau);
|
|
}
|
|
|
|
private static void ZuckerHinzufügen(Zucker zucker)
|
|
{
|
|
if (zucker.Menge > 100 && !VorkZuckers.Contains(zucker) && RemovedZuckers.All(z => z != zucker.Id))
|
|
{
|
|
VorkZuckers.Add(zucker);
|
|
}
|
|
}
|
|
|
|
private static void ObstHinzufügen(Obst obst)
|
|
{
|
|
if (VorkObsts.All(o => o.Obst != obst))
|
|
{
|
|
VorkObsts.Add(new ObstTraeger(obst));
|
|
}
|
|
}
|
|
|
|
private static void FeindHinzufügen(Ameise feind)
|
|
{
|
|
if (feind.AktuelleEnergie > 0 && !VorkFeinde.Contains(feind))
|
|
{
|
|
VorkFeinde.Add(feind);
|
|
}
|
|
}
|
|
|
|
private static void ZuckerEntfernen()//Zucker zucker
|
|
{
|
|
for (int i = 0; i < VorkZuckers.Count; )
|
|
{
|
|
var zucker = VorkZuckers[i];
|
|
if (zucker.Menge > 0)
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
if (VorkZuckers.Contains(zucker))
|
|
{
|
|
VorkZuckers.Remove(zucker);
|
|
}
|
|
if (!RemovedZuckers.Contains(zucker.Id))
|
|
{
|
|
RemovedZuckers.Add(zucker.Id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void ObstEntfernen()
|
|
{
|
|
for (int i = 0; i < VorkObsts.Count; )
|
|
{
|
|
var obst = VorkObsts[i];
|
|
if (obst.Obst.Menge > 0)
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
VorkObsts.Remove(obst);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void FeindEntfernen()
|
|
{
|
|
for (int i = 0; i < VorkFeinde.Count; )
|
|
{
|
|
var feind = VorkFeinde[i];
|
|
if (feind.AktuelleEnergie > 0)
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
VorkFeinde.Remove(feind);
|
|
GetoeteteAmeisen++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
public class ObstTraeger
|
|
{
|
|
public Obst Obst;
|
|
private readonly List<BrainArmyAntsKlasse> ameisen;
|
|
|
|
public ObstTraeger(Obst obst)
|
|
{
|
|
Obst = obst;
|
|
ameisen = new List<BrainArmyAntsKlasse>();
|
|
}
|
|
|
|
public bool BrauchtNochTraeger()
|
|
{
|
|
return ameisen.Count < 10;
|
|
}
|
|
|
|
public void AmeiseHinzufügen(BrainArmyAntsKlasse ameise)
|
|
{
|
|
if (!IstTraeger(ameise))
|
|
ameisen.Add(ameise);
|
|
}
|
|
|
|
public void AmeiseEntfernen(BrainArmyAntsKlasse ameise)
|
|
{
|
|
ameisen.Remove(ameise);
|
|
}
|
|
|
|
public bool IstTraeger(BrainArmyAntsKlasse ameise)
|
|
{
|
|
return ameisen.Contains(ameise);
|
|
}
|
|
}
|
|
}
|