Prim’s Maze Generation Algorithm on a Triangular Grid

prims_algoritthm_tri_grid_header

Below is an implementation of Prim’s Maze Generation Algorithm on a triangular grid. The example shows how to work with grid edges, and how you can use rhombille grids  to display the edges of triangular grids nicely. This example only uses five tiles, shown below:

Tile01 Tile02 Tile03 Tile04 Tile05

[button url=”https://gamelogic.co.za/examples/grids/prims-algorithm-on-a-tri-grid/” arrow=”right”]PLAY INTERACTIVE EXAMPLE[/button]

Note: You need the Unity Web Plugin to play this example.

 

Core Maze Algorithm

public static IEnumerable GenerateMazeWalls(FlatTriGrid grid)
{
   IGrid<bool, pointyrhombpoint=""> walls = grid.MakeEdgeGrid(); //true indicates passable
   List wallList = new List();

   FlatTriPoint newMaizePoint = grid.RandomItem();
   var inMaze = new List();
   inMaze.Add(newMaizePoint);

   var edges = newMaizePoint.GetEdges();
   wallList.AddRange(edges);

   while (wallList.Any())
   {
      var randomWall = wallList.RandomItem();
      IEnumerable faces = (randomWall as IEdge).GetEdgeFaces().Where(x => grid.Contains(x));

      //At least one of the two faces must be in the maze
      if (faces.Any(point => !inMaze.Contains(point)))
      {
         newMaizePoint = faces.First(point => !inMaze.Contains(point));
         inMaze.Add(newMaizePoint);
         walls[randomWall] = true;

         yield return randomWall;

         // Add all edges that are not passages
         edges = newMaizePoint.GetEdges().Where(edge => !(walls[edge]));
         wallList.AddRange(edges);
      }
      else
      {
         wallList.Remove(randomWall);
      }
   }

   yield break;
}

Shell

using UnityEngine;
using System;
using System.Collections;
using System.Linq;
using Gamelogic.Grids;

public class PrimsAlgorithm : GLMonoBehaviour, IResetable
{
   public MazeCell cellPrefab;
   public MazeCell edgePrefab;
   public GameObject root;

   private readonly Vector2 cellDimensions = new Vector2(362, 310);

   public void Start()
   {
      Reset();
   }

   public void Reset()
   {
      root.transform.DestroyChildren();

      StartCoroutine(BuildGrid());
   }   

   private IEnumerator BuildGrid()
   {
      var grid = PointyRhombGrid.Rectangle(10, 10);      
      var offset = new PointyRhombPoint(-2, -5, 0);

      grid.SetGridPointTransforms(
         p => p.MoveBy(offset),
         p => p.MoveBy(offset.Negate()));

      var map = new PointyRhombMap(cellDimensions)
         .SetGridPointTransforms(
            p => p.MoveBy(offset),
            p => p.MoveBy(offset.Negate()))
         .WithWindow(ExampleUtils.ScreenRect)
         .AlignMiddelCenter(grid)
         .Scale(.98f)         
         .Translate(25 * 3.125f, 15 * 3.125f) //Manually Center
         .To3DXY();

      foreach (var point in grid)
      {
         MazeCell cell = Instantiate(cellPrefab);
         cell.transform.parent = root.transform;
         cell.transform.localScale = Vector3.one;
         cell.transform.localPosition = map[point];      

         //Yellow         
         if (InPolygon(point, -2, 3, -3, 2, -2, 3) ||
            InSegmentY(point, 0, 2, -3) && point.I == 2 ||
            InSegmentZ(point, 1, 3, -3) && point.I == 0 ||
            InSegmentX(point, 1, 3, -4) && point.I == 1)
         {
            cell.SetOrientation(point.I, false);
         }
         // Green
         else if(InSegmentX(point, -3, 0, 3) && point.I != 1)
         {
            cell.SetOrientation(3, 2 - point.I/2);
         }
         else if(InSegmentX(point, 1, 3, -4) && point.I != 1)
         {
            cell.SetOrientation(3, 5 - point.I/2);
         }
         else if(
            InSegmentY(point, -4, -1, 4) && point.I != 2 ||
            InSegmentZ(point, 1, 3, -3) && point.I != 0)
         {
            cell.SetOrientation(3, point.I + 5);
         }
         else if(
            InSegmentY(point, 0, 2, -3) && point.I != 2 ||
            InSegmentZ(point, -3, 0, 4) && point.I != 0)
         {
            cell.SetOrientation(3, point.I + 2);
         }
         //Red
         else if(
            InSegmentX(point, -3, 0, 3) && point.I == 1 ||
            InSegmentY(point, 0, 3, -4) && point.I == 2)
         {
            cell.SetOrientation(2, point.I + 5);
         }
         else if(
            InSegmentX(point, 1, 4, -5) && point.I == 1 ||
            InSegmentY(point, -4, -1, 4) && point.I == 2)
         {
            cell.SetOrientation(2, point.I + 2);
         }
         else if(InSegmentZ(point, 1, 4, -4) && point.I == 0)
         {
            cell.SetOrientation(2, point.I + 5);
         }
         else if(InSegmentZ(point, -3, 0, 4) && point.I == 0)
         {
            cell.SetOrientation(2, point.I + 2);
         }
         else
         {
            cell.SetOrientation(4, point.I + 2);
         }

         cell.SetText("");         
         cell.SetColor(Color.white);

         grid[point] = cell;
      }

      var mazeGrid = FlatTriGrid.Hexagon(3);// Rectangle(8, 6);   
      var mazeOffset = offset.MoveBy(new PointyRhombPoint(0, 1, 0));

      foreach (var point in MazeAlgorithms.GenerateMazeWalls(mazeGrid))
      {
         var gridPoint = point.MoveBy(mazeOffset);

         if(grid.Contains(gridPoint))
         {
            grid[gridPoint].SetOrientation(point.I, true);

            yield return null;
         }
      }      
   }

    private bool InPolygon(PointyRhombPoint point, int x0, int x1, int y0, int y1, int z0, int z1)
    {
      return 
         x0 <= point.X && point.X <= x1 &&
         y0 <= point.Y && point.Y <= y1 &&
         z0 <= point.BasePoint.Z && point.BasePoint.Z <= z1;
    }

   private bool InSegmentX(PointyRhombPoint point, int x0, int x1, int y)
   {
      return x0 <= point.X && point.X <= x1 && point.Y == y;
   }

   private bool InSegmentY(PointyRhombPoint point, int y0, int y1, int x)
   {
      return y0 <= point.Y && point.Y <= y1 && point.X == x;
   }

   private bool InSegmentZ(PointyRhombPoint point, int x0, int x1, int z)
   {
      return x0 <= point.X && point.X <= x1 && point.BasePoint.Z == z;
   }
}

 

1 thought on “Prim’s Maze Generation Algorithm on a Triangular Grid”

  1. Pingback: Designing tiles for a triangular maze | Gamelogic

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top