csharp/1upD/Nails/Alife/Agents/Tunneler.cs

Tunneler.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Alife.AlifeMaps;

namespace Alife.Agents
{
    /**
     * 
     * Basic agent that digs tunnels.
     * 1upD
     * 
     */
    [Serializable]
    public clast Tunneler : BaseAgent
    {
        public int X;
        public int Y;
        public int Z;
        public int Width;
        public int Height;
        public int Lifetime;
        public int MaxLifetime;
        public float ProbReproduce;
        public float ProbTurn;
        public float ProbAscend;
        public float ProbSpawnRoomer;
        public int MaxHeightDecayRate;
        public int MinHeightDecayRate;
        public int MaxWidthDecayRate;
        public int MinWidthDecayRate;
        public string Style;
        public AlifeDirection Direction;
        public bool SpawnRoomerOnDeath;
        public int LifetimeDecayRate;
        public int MaxVerticalDrop;

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public Tunneler()
        {
            this.X = 0;
            this.Y = 0;
            this.Z = 0;
            this.Width = 1;
            this.Height = 2;
            this.Lifetime = 1;
            this.MaxLifetime = 1;
            this.ProbReproduce = 0.0f;
            this.ProbAscend = 0.0f;
            this.ProbTurn = 0.0f;
            this.Direction = 0.0f;
            this.Style = "";
            this.MaxHeightDecayRate = 0;
            this.MinHeightDecayRate = 0;
            this.MaxWidthDecayRate = 0;
            this.MinWidthDecayRate = 0;
            this.MaxVerticalDrop = 1;
            this.ProbSpawnRoomer = 0.0f;
            this.SpawnRoomerOnDeath = true;
            this.LifetimeDecayRate = 1;
        }

        /**
         * 
         * Constructor takes a lot of arguments.
         * 1upD
         * 
         */
        public Tunneler(string style = "", int x = 0, int y = 0, int z = 0,
            int width = 1, int height = 2,
            int lifetime = 1, int maxLifetime = 1,
            float probReproduce = 0.0f, float probTurn = 0.0f, float probAscend = 0.0f,
            AlifeDirection direction = AlifeDirection.East, int MaxHeighDecayRate = 0, int MinHeightDecayRate = 0, int MaxWidthDecayRate = 0, int MinWidthDecayRate = 0, float ProbSpawnRoomer = 0.0f, bool spawnRoomerOnDeath = true, int LifeTimeDecayRate = 1, int maxVerticalDrop = 2)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
            this.Width = width;
            this.Height = height;
            this.Lifetime = lifetime;
            this.MaxLifetime = maxLifetime;
            this.ProbReproduce = probReproduce;
            this.ProbAscend = probAscend;
            this.ProbTurn = probTurn;
            this.Direction = direction;
            this.Style = style;
            this.ProbSpawnRoomer = ProbSpawnRoomer;
            this.SpawnRoomerOnDeath = spawnRoomerOnDeath;
            this.LifetimeDecayRate = 1;
            this.MaxVerticalDrop = 1;

            log.Debug(string.Format("Tunneler spawned at {0}, {1}, {2}.", this.X, this.Y, this.Z));
        }

        public new void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            throw new NotImplementedException();
        }

        /**
         * 
         * Gets the remaining number of turns. Useful if this agent needs to be culled.
         * 1upD
         * 
         */
        public override int GetTurnsLeft()
        {
            return this.Lifetime;
        }

        /**
         * 
         * Step function for tunneler. Uses RNG to choose whether to turn or reproduce, then moves forward in a direction. Marks all occupied spaces in the provided map.
         * 1upD
         * 
         *
         */
        public override void Step(AlifeMap map)
        {
            try {
                int seed = this.X + this.Y + this.Z + (int)this.Direction + this.Height + this.Width + (int)System.DateTime.Now.Ticks;

                // Get random number
                Random random = new Random(seed);
                double sample = random.NextDouble();

                // Check turn probability. If turning, change direction 90 degrees
                if (sample < this.ProbTurn)
                {
                    sample = random.NextDouble();
                    int polarity = sample > 0.5 ? 1 : -1;
                    this.Direction = AlifeDirectionOperations.Add(this.Direction, polarity);
                }

                // Get new random seed
                sample = random.NextDouble();

                // Check reproduction probability
                if (sample < this.ProbReproduce)
                {
                    sample = random.NextDouble();
                    int polarity = sample > 0.5 ? 1 : -1;
                    AlifeDirection childDirection = AlifeDirectionOperations.Add(this.Direction, polarity);
                    int widthDecay = random.Next(this.MinWidthDecayRate, this.MaxWidthDecayRate);
                    int heightDecay = random.Next(this.MinHeightDecayRate, this.MaxHeightDecayRate);
                    Tunneler child = new Tunneler(this.Style, this.X, this.Y, this.Z, this.Width - widthDecay, this.Height - heightDecay, this.MaxLifetime - this.LifetimeDecayRate, this.MaxLifetime - this.LifetimeDecayRate, this.ProbReproduce, this.ProbTurn, this.ProbAscend, childDirection);
                    map.Agents.Add(child);
                }
                else
                {
                    sample = random.NextDouble();
                    if (sample < this.ProbSpawnRoomer)
                    {
                        Roomer child = new Roomer(x: this.X, y: this.Y, z: this.Z, style: this.Style, height: Math.Max(this.Height, 2), maxWidth: Math.Min(this.Width * 2, 3), mustDeploy: false);
                        map.Agents.Add(child);
                        }
                }

                // Get new random seed
                sample = random.NextDouble();

                // Check a s c e n d probability
                if (sample < this.ProbAscend)
                {
                    sample = random.NextDouble();
                        int verticalDistance = random.Next(1, Math.Min(this.Height, this.MaxVerticalDrop));
                    int polarity = sample > 0.5 ? verticalDistance : -verticalDistance;
                    this.Z += polarity;
                }
                else
                {
                    // Update location
                    switch (this.Direction)
                    {
                        case AlifeDirection.East:
                            this.X++;
                            break;
                        case AlifeDirection.North:
                            this.Y++;
                            break;
                        case AlifeDirection.West:
                            this.X--;
                            break;
                        case AlifeDirection.South:
                            this.Y--;
                            break;
                        case AlifeDirection.Up:
                            this.Z++;
                            break;
                        case AlifeDirection.Down:
                            this.Z--;
                            break;
                    }

                }


                // Mark location
                // Nasty nested four loop to handle the added spaces from the height and width
                bool vertical = this.Direction == AlifeDirection.North || this.Direction == AlifeDirection.South;
                for (int x = this.X; x