Advertisement
Guest User

Untitled

a guest
Aug 28th, 2019
432
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.71 KB | None | 0 0
  1.  
  2. // SPIDER DEATHMATCH BOX TOPOLOGY SIMULATOR in C# (run in LINQPad, a free C# code running notepad)
  3. // static variables (to be moved to a general settings object)
  4. public static Random r = new Random();
  5. public static bool MoveToBehaviour = false; // relocate to the corner where i killed and ate another spider.
  6. public static bool RunAwayBehaviour = true; // run to empty corner if other spiders present in my corner!
  7. public static float RunAwayMin = 0f; // only run from corners with spiders at least this big here!
  8. public static bool AttackSmallerBehaviour = true; // prefer smaller spiders to attack!
  9. public static int AttackMaxBehaviour = 3; // only attack corners if less than this num spiders there!
  10. public static float FlyPreference = 0.95f; // preference for eating flies over smaller spiders!
  11. public static float FightBiggerMax = 1f; // only attack corners if smaller spider than this there!
  12.  
  13. public static List<Spider> SpiderGraveyard = new List<Spider>();
  14.  
  15. public static int HungerPerRound = 10;
  16. public static int BattleDrawDifference = 25;
  17. public static int HealthPerFly = 25;
  18. public static int HungerPerFly = 50;
  19. public static int SizePerFly = 25;
  20. public static int MoultIncrement = 500; // regen legs
  21. public static int FeedingPeriod = 1;
  22. public static bool DieFromHunger = false;
  23. public static bool DieFromLimbLoss = false;
  24.  
  25. void Main()
  26. {
  27.     var rounds = 100; // number of rounds of the spider deathmatch!
  28.     int boxnum = 500; // number of spider deathmatch arenas!
  29.     int spidermin = 5; // minimum starting pool of spiderfighters!
  30.     int spidermax = 20; // excl. maximum starting pool of spiderfighters!
  31.    
  32.     string.Format("STATS:   rounds {0}: boxes={1}   min/box={2} max/box={3}",
  33.                 rounds, boxnum, spidermin, spidermax).Dump();
  34.     string.Format("BEHAV:   move={0}    run={1} maxAttack={2}   smlPref={3} flyPref={4} biggerMax={5}",
  35.                 MoveToBehaviour?1:0, RunAwayBehaviour?1:0, AttackMaxBehaviour, AttackSmallerBehaviour?1:0, FlyPreference, FightBiggerMax).Dump();
  36.    
  37.     var boxes = new List<Box>();   
  38.     for (int b = 0; b < boxnum; b++)
  39.         boxes.Add(new Box(b+1, r.Next(spidermin, spidermax)));
  40.        
  41.     //string.Format("DEATHMATCH START").Dump();
  42.     for (int round = 0; round < rounds; round++)
  43.     {
  44.         string.Format("Total spiders={0}    average per box={1}", boxes.Sum(b => b.SpiderCount), boxes.Average(b => b.Spiders.Count)).Dump();
  45.         //string.Format("ROUND {0}, FIGHT!", round+1).Dump();
  46.         foreach (var box in boxes)
  47.         {
  48.             // PZ and his students adding one fly for every spider;
  49.             if (round%FeedingPeriod==0)
  50.             {
  51.                 if (box.Flies < box.SpiderCount*2)
  52.                     box.AddFlies(box.SpiderCount*2);
  53.             }
  54.             box.ShakeFlies();
  55.             box.ShakeFlies();
  56.             box.ShakeFlies();
  57.             box.ShakeFlies();
  58.             //string.Format("   box #{0}: spiders: {1}",b.ID,b.SpiderCount).Dump();
  59.             foreach (var spider in (box.Spiders.OrderBy(s => r.Next()).Select(s => s)).ToList())
  60.             {
  61.                 // Most spider behaviour is in this method. Search for enemies, fight em!
  62.                 if (!spider.Dead)
  63.                 {
  64.                     spider.Behaviour();
  65.                 }
  66.             }
  67.         }
  68.     }
  69.     //string.Format("DEATHMATCH OVER").Dump();
  70.     string.Format("Average number of spiders in each box: {0}", boxes.Average(b => b.Spiders.Count)).Dump();
  71.    
  72.     foreach (var box in boxes)
  73.     {
  74.         string.Format(" box #{0}: spiders={1}   flies={2}",box.ID,box.SpiderCount,box.TotalFlies).Dump();
  75.         foreach (var spider in (box.Spiders).ToList())
  76.         {
  77.             string.Format("     spider #{0}:    kills={1}   size={2}    health={3}  hunger={4}  legs={5}    moults={6}  corner={7}",
  78.                 spider.ID, spider.Kills, spider.Size, spider.HealthBar, spider.HungerBar, spider.Legs, spider.Moults, spider.CurrentCorner).Dump();
  79.         }
  80.     }
  81. }
  82.  
  83. public class Spider
  84. {
  85.     public static int SPID = 0;
  86.     public int ID = 0;
  87.     public Box CurrentBox = null;
  88.     public Corner CurrentCorner = null;
  89.     public int HealthBar = 100; // 0 == dead
  90.     public int HungerBar = 0; // 100 == dead
  91.     public int Size = 100;
  92.     public int Legs = 8;
  93.     public int Moults = 1; // post-birth moult before able to fight!
  94.     public int Kills = 0;
  95.     public bool Dead = false;
  96.    
  97.     public Spider()
  98.     {
  99.         ID = SPID++;
  100.     }
  101.    
  102.     public void Behaviour()
  103.     {
  104.         this.HungerBar += HungerPerRound;
  105.         if (this.HungerBar > 50)
  106.         {
  107.             int damage = (this.HealthBar-this.HungerBar-50 < 25 ? 5 : this.HungerBar-50);
  108.                
  109.             this.HealthBar = Math.Max(0, this.HealthBar - damage);
  110.             if (this.HealthBar == 0 && DieFromHunger)
  111.             {
  112.                 this.Die();
  113.                 return;
  114.             }
  115.         }
  116.    
  117.         Corner corner = null;
  118.        
  119.         // check if local fly and if we're feeling like eating one.
  120.         if (CurrentCorner.Flies > 0 && r.NextDouble() <= FlyPreference)
  121.         {
  122.             // eat a fly, happy.
  123.             TryEatFly();
  124.             return;
  125.         }
  126.        
  127.         // check to see if anyone to chew on in current corner;
  128.         if (CurrentCorner.SpiderCount > 1)
  129.         {
  130.             corner = CurrentCorner;
  131.         }
  132.        
  133.         bool ranaway = false;
  134.         if (RunAwayBehaviour)
  135.         {          
  136.             // only run away if this corner has bigger spiders than me?
  137.             if ((from s in CurrentCorner.Spiders where s != this && this.IsBiggerThan(s) > RunAwayMin select s).Any())
  138.             {
  139.                 // prefer empty corners
  140.                 var corners = (from n in CurrentCorner.Neighbours where n.SpiderCount == 0 select n).ToList();
  141.                
  142.                 if (corners.Any())
  143.                 {
  144.                     this.MoveTo(corners[r.Next(corners.Count)]);
  145.                     corner = null;
  146.                     ranaway = true;
  147.                 }
  148.                 else
  149.                 {              
  150.                     //no empty corners so look for a corner with smaller spiders than me.
  151.                     corners = (from n in CurrentCorner.Neighbours where n.Spiders.Count(s=>this.IsBiggerThan(s) > RunAwayMin) == 0 select n).ToList();
  152.                    
  153.                     if (corners.Any())
  154.                     {
  155.                         corner = this.MoveTo(corners[r.Next(corners.Count)]);
  156.                         ranaway = true;
  157.                     }
  158.                 }
  159.             }
  160.         }
  161.        
  162.         if (corner != null)
  163.         {
  164.             var enemies = (from s in corner.Spiders where s != this && s.IsBiggerThan(this) < FightBiggerMax select s).ToList();
  165.             if (enemies.Any())
  166.             {
  167.                 var enemy = enemies[r.Next(enemies.Count)];
  168.                 this.Fight(enemy);
  169.                 return;
  170.             }
  171.             else
  172.                 TryEatFly();
  173.         }
  174.        
  175.         if (!ranaway && corner == null)
  176.         {
  177.             // check the other corners (hungrily) for spiders!
  178.             var corners = (from n in CurrentCorner.Neighbours where n.SpiderCount > 0 && n.SpiderCount <= AttackMaxBehaviour select n).ToList();
  179.             if (corners.Any())
  180.             {
  181.                 corner = corners[r.Next(corners.Count)];
  182.                 // behaviour of moving to corner with prey after fight (i.e. staying there).
  183.                 if (MoveToBehaviour)
  184.                     this.MoveTo(corner);
  185.             }
  186.         }
  187.         if (corner != null)
  188.         {
  189.             var enemies = (from s in corner.Spiders where s != this && s.IsBiggerThan(this) < FightBiggerMax select s).ToList();
  190.             if (enemies.Any())
  191.             {
  192.                 var enemy = enemies[r.Next(enemies.Count)];
  193.                 this.Fight(enemy);
  194.                 return;
  195.             }
  196.             else
  197.                 TryEatFly();
  198.         }
  199.         else // in empty corner, try to eat a fly
  200.         {
  201.             TryEatFly();
  202.         }
  203.     }
  204.    
  205.     // FIGHT!!!!
  206.     public bool? Fight(Spider enemy)
  207.     {
  208.         int myBS = this.GetBattleScore();
  209.         int enemyBS = enemy.GetBattleScore();
  210.        
  211.         if (Math.Abs(myBS-enemyBS) < BattleDrawDifference) // close fight, draw, lose health
  212.         {
  213.             this.HealthBar = Math.Max(0, this.HealthBar - 10);
  214.             enemy.HealthBar = Math.Max(0, enemy.HealthBar - 10);
  215.             return null;
  216.         }
  217.        
  218.         if (myBS > enemyBS)
  219.         {
  220.             // om nom nom nom
  221.             this.Eat(enemy);
  222.             if (myBS - enemyBS < r.Next(BattleDrawDifference*2)) // close fight, limb loss chance!
  223.                 this.Legs--;
  224.                
  225.             if (this.Legs == 0 && DieFromLimbLoss) //no legs, die!
  226.                 this.Die();
  227.             return true;
  228.         }
  229.         else
  230.         {
  231.             enemy.Eat(this);
  232.             if (enemyBS - myBS < r.Next(50)) // close fight, limb loss chance!
  233.                 enemy.Legs--;
  234.             if (enemy.Legs == 0 && DieFromLimbLoss) //no legs, die!
  235.                 enemy.Die();
  236.             return false;
  237.         }
  238.     }
  239.    
  240.     public int GetBattleScore()
  241.     {
  242.         return ((this.Size
  243.             / (this.Legs > 6 ? 1 : (8-this.Legs))) // low leg count severe penalty
  244.             - (this.HealthBar < 75 ? 0 : (this.HealthBar/5))) //low health penalty
  245.             + (this.HungerBar > 25 ? this.HungerBar < 50 ? 25 : -(this.HungerBar-50) : 0) //hunger ferocity bonus
  246.             + r.Next(200);
  247.     }
  248.    
  249.     public void TryEatFly()
  250.     {
  251.         bool eaten = false;
  252.         if (CurrentCorner.Flies > 0)
  253.         {
  254.             CurrentCorner.Flies--;
  255.             eaten  = true;
  256.         }
  257.         else if (CurrentBox.Flies > 0)
  258.         {
  259.             CurrentBox.Flies--;
  260.             eaten  = true;
  261.         }
  262.         if (eaten)
  263.         {
  264.             this.HealthBar = Math.Min(100, this.HealthBar + HealthPerFly);
  265.             this.HungerBar = Math.Max(0, this.HungerBar - HungerPerFly);
  266.             var prevSize = this.Size / MoultIncrement;
  267.             this.Size += SizePerFly;
  268.             if (prevSize < this.Size / MoultIncrement)
  269.                 this.Moult();
  270.         }
  271.     }
  272.    
  273.     public void Eat(Spider meal)
  274.     {
  275.         meal.Die();
  276.         this.Kills++;
  277.         this.HealthBar = Math.Min(100, this.HealthBar + 50);
  278.         this.HungerBar = Math.Max(0, this.HungerBar - meal.Size/2);
  279.         var prevSize = this.Size / MoultIncrement;
  280.         this.Size+=meal.Size/2;
  281.         if (prevSize < this.Size / MoultIncrement)
  282.             this.Moult();
  283.     }
  284.    
  285.     public void Moult()
  286.     {
  287.         this.Moults++;
  288.         this.HealthBar = 100;
  289.         this.HungerBar = 35;
  290.         if (r.Next(2) == 1)
  291.             this.Legs = Math.Min(8,this.Legs+1);
  292.     }
  293.    
  294.     public void Die()
  295.     {
  296.         if (this.Dead)
  297.             throw (new Exception("What is dead cannot die!"));
  298.         this.Dead = true;
  299.         this.CurrentCorner.Spiders.Remove(this);
  300.         this.CurrentBox.Spiders.Remove(this);
  301.         SpiderGraveyard.Add(this);
  302.     }
  303.    
  304.     public float IsBiggerThan(Spider friendo)
  305.     {
  306.         return ((float)this.Size)/((float)friendo.Size);
  307.     }
  308.    
  309.     public void MoveTo(Box target, Corner targetcorner)
  310.     {
  311.         if (CurrentCorner != null)
  312.             CurrentCorner.Spiders.Remove(this);
  313.         if (CurrentBox != null)
  314.             CurrentBox.Spiders.Remove(this);
  315.            
  316.         CurrentBox = target;
  317.         CurrentCorner = targetcorner;
  318.         if (target != null)
  319.             target.Spiders.Add(this);
  320.         if (targetcorner != null)
  321.             targetcorner.Spiders.Add(this);
  322.     }
  323.    
  324.     public void MoveTo(Box target)
  325.     {
  326.         this.MoveTo(target, target != null ? target.Corners[r.Next(target.Corners.Count)] : null);
  327.     }
  328.    
  329.     public Corner MoveTo(Corner target)
  330.     {
  331.         if (CurrentCorner == target)
  332.             return CurrentCorner;
  333.         if (CurrentCorner != null)
  334.             CurrentCorner.Spiders.Remove(this);
  335.         CurrentCorner = target;
  336.         if (target != null)
  337.             target.Spiders.Add(this);
  338.         return CurrentCorner;
  339.     }
  340. }
  341.    
  342. public class Box
  343. {
  344.     public int ID = 0;
  345.     public List<Spider> Spiders;
  346.     public List<Corner> Corners;
  347.    
  348.     public int SpiderCount { get { return Spiders.Count; } }
  349.     public int CornerCount { get { return Corners.Count; } }
  350.    
  351.     // flies in the middle available to everyspider;
  352.     public int Flies = 0;
  353.    
  354.     public int TotalFlies { get { return Flies + Corners.Sum(s => s.Flies);} }
  355.    
  356.     public Box(int id, int spidercount)
  357.     {
  358.         ID = id;
  359.         Spiders = new List<Spider>();
  360.         Corners = new List<Corner>();
  361.         for (int x = 0; x<2; x++)
  362.         for (int y = 0; y<2; y++)
  363.         for (int z = 0; z<2; z++)
  364.         {
  365.             var corner = new Corner(x==1, y==1, z==1);
  366.             Corners.Add(corner);
  367.         }
  368.         foreach (var c in Corners)
  369.             c.Neighbours.AddRange(from c2 in Corners where c.IsNeighbour(c2) select c2);
  370.            
  371.         for (int i = 0; i < spidercount; i++)
  372.         {
  373.             var s = new Spider();
  374.             s.MoveTo(this, Corners[r.Next(Corners.Count)]);
  375.         }
  376.     }
  377.    
  378.     public void AddFlies(int flycount)
  379.     {
  380.         for (int i = 0; i< flycount; i++)
  381.         {
  382.             int placement = r.Next(Corners.Count+1);
  383.             if (placement == 0)
  384.                 Flies++;
  385.             else
  386.                 Corners[placement-1].Flies++;
  387.         }
  388.     }
  389.    
  390.     public void ShakeFlies()
  391.     {
  392.         foreach (var emptyCorner in (from c in Corners where c.Flies > 0 && c.SpiderCount == 0 select c).ToList())
  393.         {
  394.             int flies = emptyCorner.Flies;
  395.             emptyCorner.Flies = 0;
  396.             this.AddFlies(flies);
  397.         }
  398.     }
  399. }
  400.  
  401. public class Corner
  402. {
  403.     public bool X;
  404.     public bool Y;
  405.     public bool Z;
  406.    
  407.     public List<Corner> Neighbours;
  408.     public List<Spider> Spiders;
  409.     public int SpiderCount { get { return Spiders.Count; } }
  410.     public int NeighbourCount { get { return Neighbours.Count; } }
  411.    
  412.     public int Flies = 0;
  413.    
  414.     public Corner(bool x, bool y, bool z)
  415.     {
  416.         X = x; Y = y; Z = z;
  417.         Neighbours = new List<Corner>();
  418.         Spiders = new List<Spider>();
  419.     }
  420.    
  421.     public bool IsNeighbour(Corner p)
  422.     {
  423.         return (p != null && ((X==p.X?1:0)+(Y==p.Y?1:0)+(Z==p.Z?1:0) ==2));
  424.     }
  425.    
  426.     public bool IsNeighbourOrSame(Corner p)
  427.     {
  428.         return (p != null && ((X==p.X?1:0)+(Y==p.Y?1:0)+(Z==p.Z?1:0) >=2));
  429.     }
  430.    
  431.     public override string ToString()
  432.     {
  433.         return string.Format("{0} {1} {2}", (Y?"Top":"Bottom"), (X?"Right":"Left"), (Z?"Back":"Front"));
  434.     }
  435.    
  436.     public override bool Equals(object obj)
  437.     {
  438.         return this.Equals(obj as Corner);
  439.     }
  440.  
  441.     public bool Equals(Corner p)
  442.     {
  443.         // If parameter is null, return false.
  444.         if (Object.ReferenceEquals(p, null))
  445.         {
  446.             return false;
  447.         }
  448.  
  449.         // Optimization for a common success case.
  450.         if (Object.ReferenceEquals(this, p))
  451.         {
  452.             return true;
  453.         }
  454.  
  455.         // If run-time types are not exactly the same, return false.
  456.         if (this.GetType() != p.GetType())
  457.         {
  458.             return false;
  459.         }
  460.  
  461.         // Return true if the fields match.
  462.         // Note that the base class is not invoked because it is
  463.         // System.Object, which defines Equals as reference equality.
  464.         return (X == p.X) && (Y == p.Y) && (Z == p.Z);
  465.     }
  466.  
  467.     public override int GetHashCode()
  468.     {
  469.         return (X?1:0)+(Y?2:0)+(Z?4:0);
  470.     }
  471.  
  472.     public static bool operator ==(Corner lhs, Corner rhs)
  473.     {
  474.         // Check for null on left side.
  475.         if (Object.ReferenceEquals(lhs, null))
  476.         {
  477.             if (Object.ReferenceEquals(rhs, null))
  478.             {
  479.                 // null == null = true.
  480.                 return true;
  481.             }
  482.  
  483.             // Only the left side is null.
  484.             return false;
  485.         }
  486.         // Equals handles case of null on right side.
  487.         return lhs.Equals(rhs);
  488.     }
  489.  
  490.     public static bool operator !=(Corner lhs, Corner rhs)
  491.     {
  492.         return !(lhs == rhs);
  493.     }
  494. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement