/// <summary>
 /// Generates a new maze.
 /// </summary>
 /// <param name="goal">The intended goal of the maze.</param>
 /// <returns>The intended start of the maze.</returns>
 public CoordI Generate(CoordI goal)
 {
     _walls = new bool[Size.X * Size.Y * 2];
     _flood = new int[Size.X, Size.Y];
     r_generate(goal);
     return FurthestFromGoal();
 }
        /// <summary>
        /// Finds a point in the maze that is as far or further than any other point from the goal.
        /// </summary>
        /// <returns>The furthest point in the maze from the goal.</returns>
        public CoordI FurthestFromGoal()
        {
            var largest = 0;
            var coord = new CoordI(0, 0);

            for (var x = 0; x < Size.X; ++x)
            {
                for (var y = 0; y < Size.Y; ++y)
                {
                    if (largest >= _flood[x, y]) continue;

                    largest = _flood[x, y];
                    coord.X = x;
                    coord.Y = y;
                }
            }

            return coord;
        }
 public void Generate()
 {
     Goal = new CoordI(_rand.Next(0, 2) * (_walls.Size.X - 1), _rand.Next(0, 2) * (_walls.Size.Y - 1));
     Start = _walls.Generate(Goal);
 }
 /// <summary>
 /// Obtains the one dimensional index from a CoordI for a cell and direction for a wall.
 /// </summary>
 /// <param name="c">The coordinates of the cell.</param>
 /// <param name="dir">The direction of the wall.</param>
 /// <returns>The corresponding index of the walls array.</returns>
 public int GetWall(CoordI c, int dir)
 {
     if (dir < 3)
     {
         return 2 * (c.X + c.Y * Size.X) + dir; // west, north, east
     }
     return 2 * (c.X + (c.Y + 1) * Size.X) + 1; // south
 }
 public int GetPathValue(CoordI c)
 {
     return _flood[c.X, c.Y];
 }
        /// <summary>
        /// Recursive maze generation based on the "Growing tree" algorithm.
        /// Should be invoked with the goal coordinates of the maze, and no value for f.
        /// </summary>
        /// <param name="c">Coordinates generate from.</param>
        /// <param name="f">Flood fill value for this cell.</param>
        private void r_generate(CoordI c, int f = 1)
        {
            if (_flood.Length == 0) return;
            if (_flood[c.X, c.Y] == 0)
            {
                _flood[c.X, c.Y] = f;

                _walls[GetWall(c, 0)] = true;
                _walls[GetWall(c, 1)] = true;
                if (c.X < Size.X - 1) _walls[GetWall(c, 2)] = true;
                if (c.Y < Size.Y - 1) _walls[GetWall(c, 3)] = true;

                var items = new Stack<int>(new[] { 0, 1, 2, 3 }.OrderBy(n => _rand.Next()).ToArray());

                while (items.Count > 0)
                {
                    var active = items.Pop();
                    var newC = c + Order[active];

                    if (!InBounds(newC) || _flood[newC.X, newC.Y] != 0) continue;

                    r_generate(newC, f + 1);
                    _walls[GetWall(c, active)] = false;
                }
            }
        }
 public void Reset()
 {
     Size = new CoordI(_engineSettings.MazeWidth, _engineSettings.MazeHeight);
     _walls = null;
     _flood = null;
 }
        public void Move(int x, int y)
        {
            Velocity.Origin.X = x;
            Velocity.Origin.Y = y;
            GridPos = new CoordI(Velocity.Origin);

            for (int i = 0; i < _numEyes; ++i)
                _eyes[i].Move(Velocity.Origin);
        }
 public bool InBounds(CoordI c)
 {
     return c.X >= 0 && c.X < Size.X && c.Y >= 0 && c.Y < Size.Y;
 }
 public bool InBounds(CoordI c, int dir)
 {
     return InBounds(c) && InBounds(dir) &&
            !(dir == 2 && c.X == Size.X - 1) &&
            !(dir == 3 && c.Y == Size.Y - 1);
 }
 public CoordD(CoordI other)
 {
     X = other.X;
     Y = other.Y;
 }
 public void Copy(CoordI other)
 {
     X = other.X;
     Y = other.Y;
 }
        public void Move(CoordI 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>
        /// 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>
 /// Tests if a cell and wall are out of bounds, or if it is set.
 /// </summary>
 /// <param name="c">The coordinates of the cell.</param>
 /// <param name="dir">The direction of the wall to test.</param>
 /// <returns>True if the wall is out of bounds, or if the wall is set.</returns>
 public bool test_wall(CoordI c, int dir)
 {
     return !InBounds(c, dir) || _walls[GetWall(c, dir)];
 }
        private int ScoreBot(CoordI gridPos, double energy)
        {
            var result = 0;

            var learnDistance = _engineSettings.LearnDistance;

            if (learnDistance && _walls.InBounds(gridPos))
                result += _walls.GetPathValue(gridPos);
            else if (learnDistance)
                result += 1000;

            result -= (int)energy;

            return result;
        }
        /// <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);
        }