Skip to content

Instantly share code, notes, and snippets.

@dmillerw
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmillerw/4b06fad10ebfd42a5c38 to your computer and use it in GitHub Desktop.
Save dmillerw/4b06fad10ebfd42a5c38 to your computer and use it in GitHub Desktop.
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class DrunkenGenerator {
private System.Random rand;
// Map arrays
private bool[,] Map;
private bool[,] WouldSmooth;
// Map dimensions
public int MapX = 10;
public int MapY = 10;
// How many steps to take
public int Iterations = 100;
// Cave smoothing
public bool SmoothCaves = true;
// How many neighbors are required to fill the cell
public int SmoothingNeighborStart = 2;
// How many times should the map be passed over
public int SmoothPasses = 1;
// Corridor bias - If true will continue going in the same direction as the last step
public bool CorridorBias = true;
public int CorridorBiasProbability = 50;
public int CorridorIterationHold = 0;
// Center bias - If true will try and head for the center of the map
public bool CenterBias = false;
public int CenterBiasProbablility = 50;
public int CenterIterationHold = 0;
// Origin bias - If true will try and head back to the starting point
public bool OriginBias = false;
public int OriginBiasProbablility = 50;
public int OriginIterationHold = 0;
// Whether steps can go over already active cells - Note, if the active cell is completely enclosed, it will ignore this rule
public bool RetraceSteps = false;
// Internal flag to allow for the skipping of a retrace check - Used when the current position can't walk out by normal means
private bool SkipFlagNextWalk = false;
// Starting point
public int OriginX,OriginY = 0;
// Location of the current step
private int CurrX,CurrY = 0;
// Location of previous step
private int LastX,LastY = 0;
// Last direction headed (only used if corridor bias is enabled)
private int LastDirection = -1;
public DrunkenGenerator() {
rand = new System.Random();
}
public void Build() {
Map = new bool[MapX, MapY];
WouldSmooth = new bool[MapX, MapY];
CurrX = OriginX;
CurrY = OriginY;
for (int i=0; i<Iterations; i++) {
// Sets the origin point to active, then begins walking
Map[CurrX,CurrY] = true;
Walk(i);
}
if (SmoothCaves) {
for (int i=0; i<SmoothPasses; i++) {
for (int x=0; x<MapX; x++) {
for (int y=0; y<MapY; y++) {
if (!Map[x, y] && NeighborCount(x, y) >= SmoothingNeighborStart) {
WouldSmooth[x, y] = true;
}
}
}
for (int x=0; x<MapX; x++) {
for (int y=0; y<MapY; y++) {
if (WouldSmooth[x, y]) {
Map[x, y] = true;
}
}
}
}
}
}
public bool GetCellState(int CellX, int CellY) {
if (!InMapBounds(CellX, CellY)) {
return false;
} else {
return Map[CellX, CellY];
}
}
private bool InMapBounds() {
return InMapBounds(CurrX, CurrY);
}
private bool InMapBounds(int CellX, int CellY) {
return CellX >= 0 && CellX < MapX && CellY >= 0 && CellY < MapY;
}
private void Walk(int CurrentIteration) {
LastX = CurrX;
LastY = CurrY;
int Direction = rand.Next(0, 4);
if (CorridorBias && CorridorIterationHold <= CurrentIteration && rand.Next(0, 100) < CorridorBiasProbability) {
int Last = Direction;
if (LastDirection != -1) {
Direction = LastDirection;
}
LastDirection = Last;
} else if (CenterBias && CenterIterationHold <= CurrentIteration && rand.Next(0, 100) < CenterBiasProbablility) {
Direction = GetDirectionTowardsPoint((MapX / 2), (MapY / 2));
} else if (OriginBias && OriginIterationHold <= CurrentIteration && rand.Next(0, 100) < OriginBiasProbablility) {
Direction = GetDirectionTowardsPoint(OriginX, OriginY);
}
switch(Direction) {
case 0: CurrY++; break;
case 1: CurrX++; break;
case 2: CurrY--; break;
case 3: CurrX--; break;
}
if (!InMapBounds()) {
CurrX = LastX;
CurrY = LastY;
Walk(CurrentIteration);
} else {
// If not allowed to retrace steps, and the current step would hit an active cell
if ((!RetraceSteps && Map[CurrX, CurrY]) && !SkipFlagNextWalk) {
// Get the neighbor count of the originating cell
int LastNeighborCount = NeighborCount(LastX, LastY);
// If neighbor count is less than 4, there's room for it to move, so manually walk to a free spot
if (LastNeighborCount < 4) {
if (InMapBounds(CurrX + 1, CurrY) && !Map[CurrX + 1, CurrY]) {
CurrX++;
} else if (InMapBounds(CurrX - 1, CurrY) && !Map[CurrX - 1, CurrY]) {
CurrX--;
} else if (InMapBounds(CurrX, CurrY + 1) && !Map[CurrX, CurrY + 1]) {
CurrY++;
} else if (InMapBounds(CurrX, CurrY - 1) && !Map[CurrX, CurrY - 1]) {
CurrY--;
}
} else { // Otherwise, the cell is completely enclosed and we set a flag to ignore the retrace steps flag for the next walk
SkipFlagNextWalk = true;
}
}
}
}
public int NeighborCount(int CellX, int CellY) {
int Count = 0;
for (int x=-1; x<=1; x++) {
for (int y=-1; y<=1; y++) {
if (x != 0 && y != 0) {
if (CellX + x >= 0 && CellX + x < MapX && CellY + y >= 0 && CellY + y < MapY) {
if (Map[CellX + x, CellY + y]) {
Count++;
}
}
}
}
}
return Count;
}
private int GetDirectionTowardsPoint(int DirX, int DirY) {
DirX -= CurrX;
DirY -= CurrY;
if (DirX > 0) {
DirX = 1;
} else if (DirX < 0) {
DirX = -1;
} else {
DirX = 0;
}
if (DirY > 0) {
DirY = 1;
} else if (DirY < 0) {
DirY = -1;
} else {
DirY = 0;
}
System.Random rand = new System.Random();
if (rand.NextDouble() >= 0.5) {
return DirX == 1 ? 1 : 3;
} else {
return DirY == 1 ? 0 : 2;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment