Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // SPIDER DEATHMATCH BOX TOPOLOGY SIMULATOR in C# (run in LINQPad, a free C# code running notepad)
- // static variables (to be moved to a general settings object)
- public static Random r = new Random();
- public static bool MoveToBehaviour = false; // relocate to the corner where i killed and ate another spider.
- public static bool RunAwayBehaviour = true; // run to empty corner if other spiders present in my corner!
- public static float RunAwayMin = 0f; // only run from corners with spiders at least this big here!
- public static bool AttackSmallerBehaviour = true; // prefer smaller spiders to attack!
- public static int AttackMaxBehaviour = 3; // only attack corners if less than this num spiders there!
- public static float FlyPreference = 0.95f; // preference for eating flies over smaller spiders!
- public static float FightBiggerMax = 1f; // only attack corners if smaller spider than this there!
- public static List<Spider> SpiderGraveyard = new List<Spider>();
- public static int HungerPerRound = 10;
- public static int BattleDrawDifference = 25;
- public static int HealthPerFly = 25;
- public static int HungerPerFly = 50;
- public static int SizePerFly = 25;
- public static int MoultIncrement = 500; // regen legs
- public static int FeedingPeriod = 1;
- public static bool DieFromHunger = false;
- public static bool DieFromLimbLoss = false;
- void Main()
- {
- var rounds = 100; // number of rounds of the spider deathmatch!
- int boxnum = 500; // number of spider deathmatch arenas!
- int spidermin = 5; // minimum starting pool of spiderfighters!
- int spidermax = 20; // excl. maximum starting pool of spiderfighters!
- string.Format("STATS: rounds {0}: boxes={1} min/box={2} max/box={3}",
- rounds, boxnum, spidermin, spidermax).Dump();
- string.Format("BEHAV: move={0} run={1} maxAttack={2} smlPref={3} flyPref={4} biggerMax={5}",
- MoveToBehaviour?1:0, RunAwayBehaviour?1:0, AttackMaxBehaviour, AttackSmallerBehaviour?1:0, FlyPreference, FightBiggerMax).Dump();
- var boxes = new List<Box>();
- for (int b = 0; b < boxnum; b++)
- boxes.Add(new Box(b+1, r.Next(spidermin, spidermax)));
- //string.Format("DEATHMATCH START").Dump();
- for (int round = 0; round < rounds; round++)
- {
- string.Format("Total spiders={0} average per box={1}", boxes.Sum(b => b.SpiderCount), boxes.Average(b => b.Spiders.Count)).Dump();
- //string.Format("ROUND {0}, FIGHT!", round+1).Dump();
- foreach (var box in boxes)
- {
- // PZ and his students adding one fly for every spider;
- if (round%FeedingPeriod==0)
- {
- if (box.Flies < box.SpiderCount*2)
- box.AddFlies(box.SpiderCount*2);
- }
- box.ShakeFlies();
- box.ShakeFlies();
- box.ShakeFlies();
- box.ShakeFlies();
- //string.Format(" box #{0}: spiders: {1}",b.ID,b.SpiderCount).Dump();
- foreach (var spider in (box.Spiders.OrderBy(s => r.Next()).Select(s => s)).ToList())
- {
- // Most spider behaviour is in this method. Search for enemies, fight em!
- if (!spider.Dead)
- {
- spider.Behaviour();
- }
- }
- }
- }
- //string.Format("DEATHMATCH OVER").Dump();
- string.Format("Average number of spiders in each box: {0}", boxes.Average(b => b.Spiders.Count)).Dump();
- foreach (var box in boxes)
- {
- string.Format(" box #{0}: spiders={1} flies={2}",box.ID,box.SpiderCount,box.TotalFlies).Dump();
- foreach (var spider in (box.Spiders).ToList())
- {
- string.Format(" spider #{0}: kills={1} size={2} health={3} hunger={4} legs={5} moults={6} corner={7}",
- spider.ID, spider.Kills, spider.Size, spider.HealthBar, spider.HungerBar, spider.Legs, spider.Moults, spider.CurrentCorner).Dump();
- }
- }
- }
- public class Spider
- {
- public static int SPID = 0;
- public int ID = 0;
- public Box CurrentBox = null;
- public Corner CurrentCorner = null;
- public int HealthBar = 100; // 0 == dead
- public int HungerBar = 0; // 100 == dead
- public int Size = 100;
- public int Legs = 8;
- public int Moults = 1; // post-birth moult before able to fight!
- public int Kills = 0;
- public bool Dead = false;
- public Spider()
- {
- ID = SPID++;
- }
- public void Behaviour()
- {
- this.HungerBar += HungerPerRound;
- if (this.HungerBar > 50)
- {
- int damage = (this.HealthBar-this.HungerBar-50 < 25 ? 5 : this.HungerBar-50);
- this.HealthBar = Math.Max(0, this.HealthBar - damage);
- if (this.HealthBar == 0 && DieFromHunger)
- {
- this.Die();
- return;
- }
- }
- Corner corner = null;
- // check if local fly and if we're feeling like eating one.
- if (CurrentCorner.Flies > 0 && r.NextDouble() <= FlyPreference)
- {
- // eat a fly, happy.
- TryEatFly();
- return;
- }
- // check to see if anyone to chew on in current corner;
- if (CurrentCorner.SpiderCount > 1)
- {
- corner = CurrentCorner;
- }
- bool ranaway = false;
- if (RunAwayBehaviour)
- {
- // only run away if this corner has bigger spiders than me?
- if ((from s in CurrentCorner.Spiders where s != this && this.IsBiggerThan(s) > RunAwayMin select s).Any())
- {
- // prefer empty corners
- var corners = (from n in CurrentCorner.Neighbours where n.SpiderCount == 0 select n).ToList();
- if (corners.Any())
- {
- this.MoveTo(corners[r.Next(corners.Count)]);
- corner = null;
- ranaway = true;
- }
- else
- {
- //no empty corners so look for a corner with smaller spiders than me.
- corners = (from n in CurrentCorner.Neighbours where n.Spiders.Count(s=>this.IsBiggerThan(s) > RunAwayMin) == 0 select n).ToList();
- if (corners.Any())
- {
- corner = this.MoveTo(corners[r.Next(corners.Count)]);
- ranaway = true;
- }
- }
- }
- }
- if (corner != null)
- {
- var enemies = (from s in corner.Spiders where s != this && s.IsBiggerThan(this) < FightBiggerMax select s).ToList();
- if (enemies.Any())
- {
- var enemy = enemies[r.Next(enemies.Count)];
- this.Fight(enemy);
- return;
- }
- else
- TryEatFly();
- }
- if (!ranaway && corner == null)
- {
- // check the other corners (hungrily) for spiders!
- var corners = (from n in CurrentCorner.Neighbours where n.SpiderCount > 0 && n.SpiderCount <= AttackMaxBehaviour select n).ToList();
- if (corners.Any())
- {
- corner = corners[r.Next(corners.Count)];
- // behaviour of moving to corner with prey after fight (i.e. staying there).
- if (MoveToBehaviour)
- this.MoveTo(corner);
- }
- }
- if (corner != null)
- {
- var enemies = (from s in corner.Spiders where s != this && s.IsBiggerThan(this) < FightBiggerMax select s).ToList();
- if (enemies.Any())
- {
- var enemy = enemies[r.Next(enemies.Count)];
- this.Fight(enemy);
- return;
- }
- else
- TryEatFly();
- }
- else // in empty corner, try to eat a fly
- {
- TryEatFly();
- }
- }
- // FIGHT!!!!
- public bool? Fight(Spider enemy)
- {
- int myBS = this.GetBattleScore();
- int enemyBS = enemy.GetBattleScore();
- if (Math.Abs(myBS-enemyBS) < BattleDrawDifference) // close fight, draw, lose health
- {
- this.HealthBar = Math.Max(0, this.HealthBar - 10);
- enemy.HealthBar = Math.Max(0, enemy.HealthBar - 10);
- return null;
- }
- if (myBS > enemyBS)
- {
- // om nom nom nom
- this.Eat(enemy);
- if (myBS - enemyBS < r.Next(BattleDrawDifference*2)) // close fight, limb loss chance!
- this.Legs--;
- if (this.Legs == 0 && DieFromLimbLoss) //no legs, die!
- this.Die();
- return true;
- }
- else
- {
- enemy.Eat(this);
- if (enemyBS - myBS < r.Next(50)) // close fight, limb loss chance!
- enemy.Legs--;
- if (enemy.Legs == 0 && DieFromLimbLoss) //no legs, die!
- enemy.Die();
- return false;
- }
- }
- public int GetBattleScore()
- {
- return ((this.Size
- / (this.Legs > 6 ? 1 : (8-this.Legs))) // low leg count severe penalty
- - (this.HealthBar < 75 ? 0 : (this.HealthBar/5))) //low health penalty
- + (this.HungerBar > 25 ? this.HungerBar < 50 ? 25 : -(this.HungerBar-50) : 0) //hunger ferocity bonus
- + r.Next(200);
- }
- public void TryEatFly()
- {
- bool eaten = false;
- if (CurrentCorner.Flies > 0)
- {
- CurrentCorner.Flies--;
- eaten = true;
- }
- else if (CurrentBox.Flies > 0)
- {
- CurrentBox.Flies--;
- eaten = true;
- }
- if (eaten)
- {
- this.HealthBar = Math.Min(100, this.HealthBar + HealthPerFly);
- this.HungerBar = Math.Max(0, this.HungerBar - HungerPerFly);
- var prevSize = this.Size / MoultIncrement;
- this.Size += SizePerFly;
- if (prevSize < this.Size / MoultIncrement)
- this.Moult();
- }
- }
- public void Eat(Spider meal)
- {
- meal.Die();
- this.Kills++;
- this.HealthBar = Math.Min(100, this.HealthBar + 50);
- this.HungerBar = Math.Max(0, this.HungerBar - meal.Size/2);
- var prevSize = this.Size / MoultIncrement;
- this.Size+=meal.Size/2;
- if (prevSize < this.Size / MoultIncrement)
- this.Moult();
- }
- public void Moult()
- {
- this.Moults++;
- this.HealthBar = 100;
- this.HungerBar = 35;
- if (r.Next(2) == 1)
- this.Legs = Math.Min(8,this.Legs+1);
- }
- public void Die()
- {
- if (this.Dead)
- throw (new Exception("What is dead cannot die!"));
- this.Dead = true;
- this.CurrentCorner.Spiders.Remove(this);
- this.CurrentBox.Spiders.Remove(this);
- SpiderGraveyard.Add(this);
- }
- public float IsBiggerThan(Spider friendo)
- {
- return ((float)this.Size)/((float)friendo.Size);
- }
- public void MoveTo(Box target, Corner targetcorner)
- {
- if (CurrentCorner != null)
- CurrentCorner.Spiders.Remove(this);
- if (CurrentBox != null)
- CurrentBox.Spiders.Remove(this);
- CurrentBox = target;
- CurrentCorner = targetcorner;
- if (target != null)
- target.Spiders.Add(this);
- if (targetcorner != null)
- targetcorner.Spiders.Add(this);
- }
- public void MoveTo(Box target)
- {
- this.MoveTo(target, target != null ? target.Corners[r.Next(target.Corners.Count)] : null);
- }
- public Corner MoveTo(Corner target)
- {
- if (CurrentCorner == target)
- return CurrentCorner;
- if (CurrentCorner != null)
- CurrentCorner.Spiders.Remove(this);
- CurrentCorner = target;
- if (target != null)
- target.Spiders.Add(this);
- return CurrentCorner;
- }
- }
- public class Box
- {
- public int ID = 0;
- public List<Spider> Spiders;
- public List<Corner> Corners;
- public int SpiderCount { get { return Spiders.Count; } }
- public int CornerCount { get { return Corners.Count; } }
- // flies in the middle available to everyspider;
- public int Flies = 0;
- public int TotalFlies { get { return Flies + Corners.Sum(s => s.Flies);} }
- public Box(int id, int spidercount)
- {
- ID = id;
- Spiders = new List<Spider>();
- Corners = new List<Corner>();
- for (int x = 0; x<2; x++)
- for (int y = 0; y<2; y++)
- for (int z = 0; z<2; z++)
- {
- var corner = new Corner(x==1, y==1, z==1);
- Corners.Add(corner);
- }
- foreach (var c in Corners)
- c.Neighbours.AddRange(from c2 in Corners where c.IsNeighbour(c2) select c2);
- for (int i = 0; i < spidercount; i++)
- {
- var s = new Spider();
- s.MoveTo(this, Corners[r.Next(Corners.Count)]);
- }
- }
- public void AddFlies(int flycount)
- {
- for (int i = 0; i< flycount; i++)
- {
- int placement = r.Next(Corners.Count+1);
- if (placement == 0)
- Flies++;
- else
- Corners[placement-1].Flies++;
- }
- }
- public void ShakeFlies()
- {
- foreach (var emptyCorner in (from c in Corners where c.Flies > 0 && c.SpiderCount == 0 select c).ToList())
- {
- int flies = emptyCorner.Flies;
- emptyCorner.Flies = 0;
- this.AddFlies(flies);
- }
- }
- }
- public class Corner
- {
- public bool X;
- public bool Y;
- public bool Z;
- public List<Corner> Neighbours;
- public List<Spider> Spiders;
- public int SpiderCount { get { return Spiders.Count; } }
- public int NeighbourCount { get { return Neighbours.Count; } }
- public int Flies = 0;
- public Corner(bool x, bool y, bool z)
- {
- X = x; Y = y; Z = z;
- Neighbours = new List<Corner>();
- Spiders = new List<Spider>();
- }
- public bool IsNeighbour(Corner p)
- {
- return (p != null && ((X==p.X?1:0)+(Y==p.Y?1:0)+(Z==p.Z?1:0) ==2));
- }
- public bool IsNeighbourOrSame(Corner p)
- {
- return (p != null && ((X==p.X?1:0)+(Y==p.Y?1:0)+(Z==p.Z?1:0) >=2));
- }
- public override string ToString()
- {
- return string.Format("{0} {1} {2}", (Y?"Top":"Bottom"), (X?"Right":"Left"), (Z?"Back":"Front"));
- }
- public override bool Equals(object obj)
- {
- return this.Equals(obj as Corner);
- }
- public bool Equals(Corner p)
- {
- // If parameter is null, return false.
- if (Object.ReferenceEquals(p, null))
- {
- return false;
- }
- // Optimization for a common success case.
- if (Object.ReferenceEquals(this, p))
- {
- return true;
- }
- // If run-time types are not exactly the same, return false.
- if (this.GetType() != p.GetType())
- {
- return false;
- }
- // Return true if the fields match.
- // Note that the base class is not invoked because it is
- // System.Object, which defines Equals as reference equality.
- return (X == p.X) && (Y == p.Y) && (Z == p.Z);
- }
- public override int GetHashCode()
- {
- return (X?1:0)+(Y?2:0)+(Z?4:0);
- }
- public static bool operator ==(Corner lhs, Corner rhs)
- {
- // Check for null on left side.
- if (Object.ReferenceEquals(lhs, null))
- {
- if (Object.ReferenceEquals(rhs, null))
- {
- // null == null = true.
- return true;
- }
- // Only the left side is null.
- return false;
- }
- // Equals handles case of null on right side.
- return lhs.Equals(rhs);
- }
- public static bool operator !=(Corner lhs, Corner rhs)
- {
- return !(lhs == rhs);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement