public Bot(Maze maze, EngineSettings engineSettings, WallGrid walls, BrainFactory brainFactory, EyeFactory eyeFactory)
        {
            _maze = maze;
            _engineSettings = engineSettings;
            _walls = walls;
            _numEyes = engineSettings.BotEyes;
            _energyStep = 1.0;

            var neurons = _numEyes +
                          (engineSettings.ThinkDistance ? 1 : 0) +
                          (engineSettings.ThinkPath ? 5 : 0) +
                          (engineSettings.ThinkVelocity ? 3 : 0);

            Brain = brainFactory.Create(neurons, 2);
            _eyes = new Eye[_numEyes];
            Velocity = new Ray(new CoordD(0.5, 0.5), 0.0, engineSettings.BotSpeed);

            for (var i = 0; i < _numEyes; ++i)
            {
                var theta = i / (double)_numEyes * Consts.HalfTurn - Consts.QuarterTurn;
                _eyes[i] = eyeFactory.Create(Velocity.Origin, 2, 0, theta, 100);
            }

            Init(new CoordD(.5,.5));
        }
        /// <summary>
        /// Draws with a given pen and differed length.
        /// </summary>
        /// <param name="e">Event data.</param>
        /// <param name="ray"></param>
        /// <param name="p">The <c>Pen</c> to use.</param>
        /// <param name="val">Length.</param>
        public void Draw(PaintEventArgs e, Ray ray, Pen p, double val)
        {
            var cellScaling = new CoordD(_settings.WinWidth / (double)_engineSettings.MazeWidth, _settings.WinHeight / (double)_engineSettings.MazeHeight);

            var end = ray.Origin.ByAngle(ray.Angle, val);

            if (ray.Origin.X * cellScaling.X >= e.ClipRectangle.X && ray.Origin.X * cellScaling.X < e.ClipRectangle.Width &&
                ray.Origin.Y * cellScaling.Y >= e.ClipRectangle.Y && ray.Origin.Y * cellScaling.Y < e.ClipRectangle.Height)
                e.Graphics.DrawLine(p,
                    new PointF((float)ray.Origin.X * (float)cellScaling.X, (float)ray.Origin.Y * (float)cellScaling.Y),
                    new PointF((float)end.X * (float)cellScaling.X, (float)end.Y * (float)cellScaling.Y));
        }
        /// <summary>
        /// Draws with the alpha channel of a given pen modified by <c>v</c>.
        /// </summary>
        /// <param name="e">Event data.</param>
        /// <param name="ray"></param>
        /// <param name="p">The <c>Pen</c> to use.</param>
        public void Draw(PaintEventArgs e, Ray ray, Pen p)
        {
            var cellScaling = new CoordD(_settings.WinWidth / (double)_engineSettings.MazeWidth, _settings.WinHeight / (double)_engineSettings.MazeHeight);

            var p1 = new Pen(Color.FromArgb((int)((1.0 - Math.Max(0.0, ray.Velocity)) * 240) + 15, p.Color.R, p.Color.G, p.Color.B));
            var end = ray.CastPoint();

            if (ray.Origin.X * cellScaling.X >= e.ClipRectangle.X && ray.Origin.X * cellScaling.X < e.ClipRectangle.Width &&
                ray.Origin.Y * cellScaling.Y >= e.ClipRectangle.Y && ray.Origin.Y * cellScaling.Y < e.ClipRectangle.Height)
                e.Graphics.DrawLine(p1,
                    new PointF((float)ray.Origin.X * (float)cellScaling.X, (float)ray.Origin.Y * (float)cellScaling.Y),
                    new PointF((float)end.X * (float)cellScaling.X, (float)end.Y * (float)cellScaling.Y));
        }
        /// <summary>
        /// Raycasts a given <c>Ray</c> in this maze.
        /// </summary>
        /// <param name="ray">The <c>Ray</c> to cast.</param>
        /// <param name="radius">The radius of the thing casting the ray.</param>
        public void Raycast(ref Ray ray, double radius)
        {
            if (Math.Abs(ray.Magnitude) < Double.Epsilon)
            {
                ray.Velocity = 0;
                return;
            }

            var gridCoords = new CoordI(ray.Origin);
            double len = 0;
            double ax;
            double ay;

            var walled = false;
            var south = ray.GoingSouth();
            var east = ray.GoingEast();

            if ((south && !east) || (!south && east))
            {
                ax = 1.0 / Math.Cos(Consts.QuarterTurn - ray.Angle % Consts.QuarterTurn);
                ay = 1.0 / Math.Cos(ray.Angle % Consts.QuarterTurn);
            }
            else
            {
                ax = 1.0 / Math.Cos(ray.Angle % Consts.QuarterTurn);
                ay = 1.0 / Math.Cos(Consts.QuarterTurn - ray.Angle % Consts.QuarterTurn);
            }

            var testCoord = ray.Origin - gridCoords;
            var testSpace = new CoordD(1,1) - testCoord;

            if (_walls.test_wall(gridCoords, 2) && testSpace.X < radius)
                ray.Origin.X -= radius - testSpace.X;
            else if (_walls.test_wall(gridCoords, 3) && testSpace.Y < radius)
                ray.Origin.Y -= radius - testSpace.Y;
            else if (_walls.test_wall(gridCoords, 0) && testCoord.X < radius)
                ray.Origin.X += radius - testCoord.X;
            else if (_walls.test_wall(gridCoords, 1) && testCoord.Y < radius)
                ray.Origin.Y += radius - testCoord.Y;

            while (len < ray.Magnitude && !walled)
            {
                var gridSpace = ray.Origin.ByAngle(ray.Angle, len) - gridCoords;
                var cellSpace = new CoordD(1,1) - gridSpace;
                gridSpace.Abs();
                cellSpace.Abs();

                var hx = (east ? cellSpace.X : gridSpace.X) * ax;
                var hy = (south ? cellSpace.Y : gridSpace.Y) * ay;

                if (hx < hy)
                    len += (east ? Math.Max(0, cellSpace.X - radius) : Math.Max(0, gridSpace.X - radius)) * ax;
                else
                    len += (south ? Math.Max(0, cellSpace.Y - radius) : Math.Max(0, gridSpace.Y - radius)) * ay;

                var dir = hx < hy ? 0 : 1;
                if ((hx < hy && east) || (hx >= hy && south)) dir += 2;

                walled = !_walls.InBounds(gridCoords, dir) || _walls.test_wall(gridCoords, dir);

                if (walled) continue;

                switch (dir)
                {
                    case 0:
                        gridCoords.X -= 1;
                        break;
                    case 1:
                        gridCoords.Y -= 1;
                        break;
                    case 2:
                        gridCoords.X += 1;
                        break;
                    case 3:
                        gridCoords.Y += 1;
                        break;
                }
            }

            ray.Velocity = Math.Min(len, ray.Magnitude) / ray.Magnitude;
        }
 /// <summary>
 /// Draws with the a default colour.
 /// </summary>
 /// <param name="e">Event data.</param>
 /// <param name="ray"></param>
 public void Draw(PaintEventArgs e, Ray ray)
 {
     Draw(e, ray, new Pen(Color.FromArgb(255, 191, 255, 0)));
 }