/// <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(furthest_from_goal()); }
/// <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[c.x, c.y] == 0) { flood[c.x, c.y] = f; walls[get_wall(c, 0)] = true; walls[get_wall(c, 1)] = true; if (c.x < size.x - 1) { walls[get_wall(c, 2)] = true; } if (c.y < size.y - 1) { walls[get_wall(c, 3)] = true; } Stack <int> items = new Stack <int>(new int[] { 0, 1, 2, 3 }.OrderBy(n => rand.Next()).ToArray()); while (items.Count > 0) { int active = items.Pop(); CoordI new_c = c + order[active]; if (in_bounds(new_c) && flood[new_c.x, new_c.y] == 0) { r_generate(new_c, f + 1); walls[get_wall(c, active)] = false; } } } }
/// <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 get_wall(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 void move(CoordI pos) { velocity.O.x = pos.x; velocity.O.y = pos.y; grid_pos = new CoordI(velocity.O / m.cell_size); for (int i = 0; i < num_eyes; ++i) { eyes[i].move(velocity.O); } }
/// <summary> /// Initialise in a given position. /// </summary> /// <param name="pos">The position to move to.</param> public void init(CoordD pos) { max_energy = Program.settings.maze_time; num_eyes = Program.settings.bot_eyes; radius = Program.settings.bot_radius; alive = true; goal = false; energy = max_energy; grid_pos = new CoordI(pos / m.cell_size); move(pos); turn_to(0.0); }
/// <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 furthest_from_goal() { int largest = 0; CoordI coord = new CoordI(0, 0); for (int x = 0; x < size.x; ++x) { for (int y = 0; y < size.y; ++y) { if (largest < flood[x, y]) { largest = flood[x, y]; coord.x = x; coord.y = y; } } } return(coord); }
/// <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 (ray.r == 0) { ray.v = 0; return; } CoordI grid_coords = new CoordI(ray.O / cell_size); int dir = -1; double len = 0; double Ax; double Ay; bool walled = false; bool south = ray.going_south(); bool east = ray.going_east(); if ((south && !east) || (!south && east)) { Ax = 1.0 / Math.Cos(Consts.η - ray.θ % Consts.η); Ay = 1.0 / Math.Cos(ray.θ % Consts.η); } else { Ax = 1.0 / Math.Cos(ray.θ % Consts.η); Ay = 1.0 / Math.Cos(Consts.η - ray.θ % Consts.η); } CoordD test_coord = ray.O - grid_coords * cell_size; CoordD test_space = cell_size - test_coord; if (walls.test_wall(grid_coords, 2) && test_space.x < radius) { ray.O.x -= radius - test_space.x; } else if (walls.test_wall(grid_coords, 3) && test_space.y < radius) { ray.O.y -= radius - test_space.y; } else if (walls.test_wall(grid_coords, 0) && test_coord.x < radius) { ray.O.x += radius - test_coord.x; } else if (walls.test_wall(grid_coords, 1) && test_coord.y < radius) { ray.O.y += radius - test_coord.y; } while (len < ray.r && !walled) { CoordD grid_space = ray.O.by_angle(ray.θ, len) - grid_coords * cell_size; CoordD cell_space = cell_size - grid_space; grid_space.abs(); cell_space.abs(); double hx = (east ? cell_space.x : grid_space.x) * Ax; double hy = (south ? cell_space.y : grid_space.y) * Ay; if (hx < hy) { len += (east ? Math.Max(0, cell_space.x - radius) : Math.Max(0, grid_space.x - radius)) * Ax; } else { len += (south ? Math.Max(0, cell_space.y - radius) : Math.Max(0, grid_space.y - radius)) * Ay; } dir = hx < hy ? 0 : 1; if ((hx < hy && east) || (hx >= hy && south)) { dir += 2; } walled = !walls.in_bounds(grid_coords, dir) || walls.test_wall(grid_coords, dir); if (!walled) { if (dir == 0) { grid_coords.x -= 1; } else if (dir == 1) { grid_coords.y -= 1; } else if (dir == 2) { grid_coords.x += 1; } else if (dir == 3) { grid_coords.y += 1; } } } ray.v = Math.Min(len, ray.r) / ray.r; }
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); }
public void copy(CoordI other) { this.x = other.x; this.y = other.y; }
/// <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(!in_bounds(c, dir) || walls[get_wall(c, dir)]); }
public bool in_bounds(CoordI c, int dir) { return(in_bounds(c) && in_bounds(dir) && !(dir == 2 && c.x == size.x - 1) && !(dir == 3 && c.y == size.y - 1)); }
public bool in_bounds(CoordI c) { return(c.x >= 0 && c.x < size.x && c.y >= 0 && c.y < size.y); }
public CoordI(CoordI other) { this.x = other.x; this.y = other.y; }
public int get_path_value(CoordI c) { return(flood[c.x, c.y]); }
public Wall_grid(int x, int y) { size = new CoordI(x, y); walls = null; flood = null; }