MakeDungeonMap()
public class DungeonMapMaker
{
<summary>
</summary>
<param name="w"></param>
<param name="h"></param>
public void MakeDungeonMap(int w, int h)
{
Random rand = new Random();
Map_W = w;
Map_H = h;
Map = MakeLikeADungeonMap(24);
OutputToImageFile();
for (; ; )
{
Point[] cps = AllClosedAreaPoints().ToArray();
if (cps.Length == 1)
break;
ClosedArea[] cas = AllClosedAreas(cps).ToArray();
Array.Sort(cas, (a, b) => a.Size - b.Size);
ClosedArea ca = cas[0];
Point[] breakingWalls = GetBreakingWalls(ca).ToArray();
if (breakingWalls.Length == 0)
{
Fill(ca.Pt.X, ca.Pt.Y, 1);
OutputToImageFile();
continue;
}
Point breakingWall = breakingWalls[rand.Next(breakingWalls.Length)];
Map[breakingWall.X, breakingWall.Y] = 0;
OutputToImageFile();
Fill(breakingWall.X, breakingWall.Y, 2);
OutputToImageFile();
Fill(breakingWall.X, breakingWall.Y, 0);
OutputToImageFile();
}
{
Point[] pts = AllPoints().Where(p => Map[p.X, p.Y] == 0).ToArray();
Point startPt = default(Point);
Point goalPt = pts[rand.Next(pts.Length)];
for (int c = 0; c < 10; c++)
{
startPt = goalPt;
pts = Farthest(startPt);
goalPt = pts[rand.Next(pts.Length)];
}
Map[startPt.X, startPt.Y] = 2;
Map[goalPt.X, goalPt.Y] = 2;
}
OutputToImageFile();
}
private int Map_W;
private int Map_H;
private int[,] Map;
private class ClosedArea
{
public Point Pt;
public int Size;
}
private IEnumerable<Point> GetBreakingWalls(ClosedArea ca)
{
Fill(ca.Pt.X, ca.Pt.Y, 2);
OutputToImageFile();
for (int x = 1; x < Map_W - 1; x++)
{
for (int y = 1; y < Map_H - 1; y++)
{
if (
Map[x - 1, y] == 0 ||
Map[x + 1, y] == 0 ||
Map[x, y + 1] == 0 ||
Map[x, y - 1] == 0
)
if (
Map[x - 1, y] == 2 ||
Map[x + 1, y] == 2 ||
Map[x, y + 1] == 2 ||
Map[x, y - 1] == 2
)
yield return new Point(x, y);
}
}
}
private IEnumerable<ClosedArea> AllClosedAreas(Point[] cps)
{
foreach (Point pt in cps)
{
if (Map[pt.X, pt.Y] == 0)
{
Fill(pt.X, pt.Y, 2);
int size = AllPoints().Where(p => Map[p.X, p.Y] == 2).Count();
Fill(pt.X, pt.Y, 0);
yield return new ClosedArea() { Pt = pt, Size = size, };
}
}
AllPoints().Where(p => Map[p.X, p.Y] == 2).ToList().ForEach(p => Map[p.X, p.Y] = 0);
}
private IEnumerable<Point> AllClosedAreaPoints()
{
foreach (Point pt in AllPoints())
{
if (Map[pt.X, pt.Y] == 0)
{
Fill(pt.X, pt.Y, 2);
yield return pt;
}
}
AllPoints().Where(p => Map[p.X, p.Y] == 2).ToList().ForEach(p => Map[p.X, p.Y] = 0);
}
private IEnumerable<Point> AllPoints()
{
for (int x = 0; x < Map_W; x++)
{
for (int y = 0; y < Map_H; y++)
{
yield return new Point(x, y);
}
}
}
private void Fill(int x, int y, int fillValue)
{
int targValue = Map[x, y];
if (targValue == fillValue)
throw null;
Queue<Point> seekers = new Queue<Point>();
seekers.Enqueue(new Point(x, y));
while (1 <= seekers.Count)
{
Point pt = seekers.Dequeue();
if (
pt.X < 0 || Map_W <= pt.X ||
pt.Y < 0 || Map_H <= pt.Y
)
continue;
if (Map[pt.X, pt.Y] != targValue)
continue;
Map[pt.X, pt.Y] = fillValue;
seekers.Enqueue(new Point(pt.X + 1, pt.Y));
seekers.Enqueue(new Point(pt.X - 1, pt.Y));
seekers.Enqueue(new Point(pt.X, pt.Y + 1));
seekers.Enqueue(new Point(pt.X, pt.Y - 1));
}
}
private Point[] Farthest(Point startPt)
{
{
Map[startPt.X, startPt.Y] = 2;
OutputToImageFile();
Map[startPt.X, startPt.Y] = 0;
}
List<Point> farthestPts = null;
List<Point> pts = new List<Point>();
pts.Add(startPt);
for (; ; )
{
List<Point> acceptPts = new List<Point>();
List<Point> nextPts = new List<Point>();
foreach (Point pt in pts)
{
if (
pt.X < 0 || Map_W <= pt.X ||
pt.Y < 0 || Map_H <= pt.Y
)
continue;
if (Map[pt.X, pt.Y] != 0)
continue;
Map[pt.X, pt.Y] = 2;
acceptPts.Add(pt);
nextPts.Add(new Point(pt.X + 1, pt.Y));
nextPts.Add(new Point(pt.X - 1, pt.Y));
nextPts.Add(new Point(pt.X, pt.Y + 1));
nextPts.Add(new Point(pt.X, pt.Y - 1));
}
if (nextPts.Count == 0)
break;
farthestPts = acceptPts;
pts = nextPts;
}
AllPoints().Where(p => Map[p.X, p.Y] == 2).ToList().ForEach(p => Map[p.X, p.Y] = 0);
{
farthestPts.ForEach(p => Map[p.X, p.Y] = 2);
OutputToImageFile();
farthestPts.ForEach(p => Map[p.X, p.Y] = 0);
}
return farthestPts.ToArray();
}
private int ImageIndex = 0;
private void OutputToImageFile()
{
using (Bitmap bmp = new Bitmap(Map_W, Map_H))
{
for (int x = 0; x < Map_W; x++)
{
for (int y = 0; y < Map_H; y++)
{
Color color;
switch (Map[x, y])
{
case 0: color = Color.Gray; break;
case 1: color = Color.Yellow; break;
case 2: color = Color.Red; break;
default:
throw null;
}
bmp.SetPixel(x, y, color);
}
}
bmp.Save(string.Format(@"C:\temp\{0}.bmp", (ImageIndex++).ToString("D4")), ImageFormat.Bmp);
}
}
private int[,] MakeLikeADungeonMap(int pattern)
{
Random rand = new Random();
int[,] map = new int[Map_W, Map_H];
for (int x = 0; x < Map_W; x++)
{
for (int y = 0; y < Map_H; y++)
{
map[x, y] = rand.Next(2);
}
}
for (int c = 0; c < Map_W * Map_H * 30; c++)
{
int x = rand.Next(Map_W);
int y = rand.Next(Map_H);
int count = 0;
for (int xc = -1; xc <= 1; xc++)
{
for (int yc = -1; yc <= 1; yc++)
{
count += map[(x + Map_W + xc) % Map_W, (y + Map_H + yc) % Map_H];
}
}
map[x, y] = (pattern >> count) & 1;
}
return map;
}
}