public void Draw(PaintEventArgs e)
        {
            var cellScaling = new CoordD(_settings.WinWidth / (double)_engineSettings.MazeWidth, _settings.WinHeight / (double)_engineSettings.MazeHeight);

            for (var x = 0; x < _walls.Size.X; ++x)
            {
                for (var y = 0; y < _walls.Size.Y; ++y)
                {
                    for (var d = 0; d < 2; ++d)
                    {
                        if (!_walls.test_wall(x, y, d)) continue;
                        var x1 = x * (float) cellScaling.X;
                        var y1 = y * (float) cellScaling.Y;

                        e.Graphics.DrawLine(Pens.White, x1, y1,
                            x1 + (d == 0 ? 0 : (float) cellScaling.X),
                            y1 + (d == 1 ? 0 : (float) cellScaling.Y)
                            );
                    }
                }
            }

            e.Graphics.DrawLine(Pens.White, (float) cellScaling.X *_walls.Size.X, 0, (float) cellScaling.X *_walls.Size.X, (float) cellScaling.Y *_walls.Size.Y);
            e.Graphics.DrawLine(Pens.White, 0, (float) cellScaling.Y *_walls.Size.Y, (float) cellScaling.X *_walls.Size.X, (float) cellScaling.Y *_walls.Size.Y);

            var r1 = new Rectangle((int)(_maze.Start.X *cellScaling.X), (int)(_maze.Start.Y *cellScaling.Y), (int) cellScaling.X, (int) cellScaling.Y);
            e.Graphics.DrawString("S", Font, Brushes.Red, r1, _fontFormat);

            var r2 = new Rectangle((int)(_maze.Goal.X *cellScaling.X), (int)(_maze.Goal.Y *cellScaling.Y), (int) cellScaling.X, (int) cellScaling.Y);
            e.Graphics.DrawString("G", Font, Brushes.Green, r2, _fontFormat);
        }
        public void Move(int x, int y)
        {
            var cellScaling = new CoordD(_settings.WinWidth / (double)_engineSettings.MazeWidth, _settings.WinHeight / (double)_engineSettings.MazeHeight);

            Position.X = x / cellScaling.X;
            Position.Y = y / cellScaling.Y;

            foreach (var eye in Eyes)
                eye.Ray.Origin.Copy(Position);
        }
        /// <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));
        }
        public void Draw(PaintEventArgs e, Bot bot)
        {
            var cellScaling = new CoordD(_settings.WinWidth / (double)_engineSettings.MazeWidth, _settings.WinHeight / (double)_engineSettings.MazeHeight);

            if (bot.Goal)
                foreach (var eye in bot._eyes)
                    _eyeDrawer.Draw(e, eye, Pens.PowderBlue);
            else if (bot.Alive)
                foreach (var eye in bot._eyes)
                    _eyeDrawer.Draw(e, eye, Pens.GreenYellow);
            else
                foreach (var eye in bot._eyes)
                    _eyeDrawer.Draw(e, eye, Pens.Red);

            _rayDrawer.Draw(e, bot.Velocity, Pens.Purple, 10*bot._speed);
            e.Graphics.DrawEllipse(Pens.CornflowerBlue,
                (float) ((bot.Velocity.Origin.X - _engineSettings.BotRadius)*cellScaling.X),
                (float) ((bot.Velocity.Origin.Y - _engineSettings.BotRadius)*cellScaling.Y),
                (float) (2*_engineSettings.BotRadius*cellScaling.X), (float) (2*_engineSettings.BotRadius*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;
        }
 public CoordD(CoordD other)
 {
     X = other.X;
     Y = other.Y;
 }
 public bool Equals(CoordD other)
 {
     return X.Equals(other.X) && Y.Equals(other.Y);
 }
 public void Copy(CoordD other)
 {
     X = other.X;
     Y = other.Y;
 }
        /// <summary>
        /// Use the <c>Brain</c> with variable inputs based on <c>_engineSettings</c>.
        /// </summary>
        public void Think()
        {
            if (!Alive) return;

            for (int i = 0; i < _numEyes; ++i)
                Brain.SetInput(i, (float)_eyes[i].Ray.Velocity);

            var extra = 0;

            if (_engineSettings.ThinkDistance)
            {
                Brain.SetInput(_numEyes + extra++, (float)(((_maze.Goal - Velocity.Origin) / (_walls.Size + 1)).Length()));
            }

            if (_engineSettings.ThinkPath)
            {
                var thisPos = _walls.GetPathValue(_maze.Start) + 1;

                if (_walls.InBounds(GridPos))
                    thisPos = _walls.GetPathValue(GridPos);

                Brain.SetInput(_numEyes + extra++, thisPos / (float)_walls.GetPathValue(_maze.Start));

                var dir = 0;
                if (Velocity.NorthQuad()) dir = 1;
                else if (Velocity.EastQuad()) dir = 2;
                else if (Velocity.SouthQuad()) dir = 3;

                for (var i = 0; i < 4; ++i)
                {
                    var index = (i + dir) % 4;
                    if (_walls.test_wall(GridPos, index) || thisPos < _walls.GetPathValue(GridPos + WallGrid.Order[index]))
                        Brain.SetInput(_numEyes + extra++, 0);
                    else
                        Brain.SetInput(_numEyes + extra++, 1);
                }
            }

            if (_engineSettings.ThinkVelocity)
            {
                var magnitude = new CoordD(0, 0).ByAngle(Velocity.Angle, 1.0);

                Brain.SetInput(_numEyes + extra++, (float)magnitude.X);
                Brain.SetInput(_numEyes + extra++, (float)magnitude.Y);
                Brain.SetInput(_numEyes + extra, (float)_speed);
            }

            Brain.Think();

            Act(Brain.GetOutput(0), Brain.GetOutput(1));
        }
        public void Move(CoordD pos)
        {
            Velocity.Origin.X = pos.X;
            Velocity.Origin.Y = pos.Y;
            GridPos = new CoordI(Velocity.Origin);

            for (int i = 0; i < _numEyes; ++i)
                _eyes[i].Move(Velocity.Origin);
        }
        /// <summary>
        /// Initialise in a given position.
        /// </summary>
        /// <param name="pos">The position to Move to.</param>
        public void Init(CoordD pos)
        {
            _maxEnergy = _engineSettings.MazeTime;
            _numEyes = _engineSettings.BotEyes;
            _radius = _engineSettings.BotRadius;

            Alive = true;
            Goal = false;
            Energy = _maxEnergy;
            GridPos = new CoordI(pos);

            Move(pos);
            turn_to(0.0);
        }