Files
csharp-brain-army-ants/BrainArmyAnts/BrainArmyAntsKlasse.cs
Sebastian Seedorf b82e014bd4 Initial commit
2020-02-16 16:40:20 +01:00

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);
}
}
}