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