Difference between revisions of "C-Sharp Example of Dungeon-Building Algorithm"

From RogueBasin
Jump to navigation Jump to search
 
m (Hexman moved page Java Example of Dungeon-Building Algorithm to C-Sharp Example of Dungeon-Building Algorithm: The code example given is in C#. Though syntactically similar, C# is a different programming language created by Microsoft for the .N...)
 
(14 intermediate revisions by 7 users not shown)
Line 1: Line 1:
(Made by [[Solarnus]])
(Made by [[Solarnus]])
<small>
<pre>
import java.lang.Integer; //so we can use Integer.parseInt()


import java.util.*; //and for getting today's date
This code is C#, not Java




<source lang="csharp">


public class dungen{
    public class Dungeon
//max size of the map
      {
   
        // misc. messages to print
        const string MsgXSize = "X size of dungeon: \t";
   
        const string MsgYSize = "Y size of dungeon: \t";
   
        const string MsgMaxObjects = "max # of objects: \t";
   
        const string MsgNumObjects = "# of objects made: \t";
   
        // max size of the map
        int xmax = 80; //columns
        int ymax = 25; //rows
   
        // size of the map
        int _xsize;
        int _ysize;
   
        // number of "objects" to generate on the map
        int _objects;
   
        // define the %chance to generate either a room or a corridor on the map
        // BTW, rooms are 1st priority so actually it's enough to just define the chance
        // of generating a room
        const int ChanceRoom = 75;
   
        // our map
        Tile[] _dungeonMap = { };
   
        readonly IRandomize _rnd;
   
        readonly Action<string> _logger;
   
   
        public Dungeon(IRandomize rnd, Action<string> logger)
        {
            _rnd = rnd;
            _logger = logger;
        }
       
        public int Corridors
        {
            get;
            private set;
        }
   
        public static bool IsWall(int x, int y, int xlen, int ylen, int xt, int yt, Direction d)
        {
            Func<int, int, int> a = GetFeatureLowerBound;
           
            Func<int, int, int> b = IsFeatureWallBound;
            switch (d)
            {
                case Direction.North:
                    return xt == a(x, xlen) || xt == b(x, xlen) || yt == y || yt == y - ylen + 1;
                case Direction.East:
                    return xt == x || xt == x + xlen - 1 || yt == a(y, ylen) || yt == b(y, ylen);
                case Direction.South:
                    return xt == a(x, xlen) || xt == b(x, xlen) || yt == y || yt == y + ylen - 1;
                case Direction.West:
                    return xt == x || xt == x - xlen + 1 || yt == a(y, ylen) || yt == b(y, ylen);
            }
           
            throw new InvalidOperationException();
        }
   
        public static int GetFeatureLowerBound(int c, int len)
        {
            return c - len / 2;
        }
   
        public static int IsFeatureWallBound(int c, int len)
        {
            return c + (len - 1) / 2;
        }
   
        public static int GetFeatureUpperBound(int c, int len)
        {
            return c + (len + 1) / 2;
        }
   
        public static IEnumerable<PointI> GetRoomPoints(int x, int y, int xlen, int ylen, Direction d)
        {
            // north and south share the same x strategy
            // east and west share the same y strategy
            Func<int, int, int> a = GetFeatureLowerBound;
            Func<int, int, int> b = GetFeatureUpperBound;
   
            switch (d)
            {
                case Direction.North:
                    for (var xt = a(x, xlen); xt < b(x, xlen); xt++) for (var yt = y; yt > y - ylen; yt--) yield return new PointI { X = xt, Y = yt };
                    break;
                case Direction.East:
                    for (var xt = x; xt < x + xlen; xt++) for (var yt = a(y, ylen); yt < b(y, ylen); yt++) yield return new PointI { X = xt, Y = yt };
                    break;
                case Direction.South:
                    for (var xt = a(x, xlen); xt < b(x, xlen); xt++) for (var yt = y; yt < y + ylen; yt++) yield return new PointI { X = xt, Y = yt };
                    break;
                case Direction.West:
                    for (var xt = x; xt > x - xlen; xt--) for (var yt = a(y, ylen); yt < b(y, ylen); yt++) yield return new PointI { X = xt, Y = yt };
                    break;
                default:
                    yield break;
            }
        }
   
        public Tile GetCellType(int x, int y)
        {
            try
            {
                return this._dungeonMap[x + this._xsize * y];
            }
            catch (IndexOutOfRangeException)
            {
                new { x, y }.Dump("exceptional");
                throw;
            }
        }
   
        public int GetRand(int min, int max)
        {
            return _rnd.Next(min, max);
        }
   
        public bool MakeCorridor(int x, int y, int length, Direction direction)
        {
            // define the dimensions of the corridor (er.. only the width and height..)
            int len = this.GetRand(2, length);
            const Tile Floor = Tile.Corridor;
   
            int xtemp;
            int ytemp = 0;
   
            switch (direction)
            {
                case Direction.North:
                    // north
                    // check if there's enough space for the corridor
                    // start with checking it's not out of the boundaries
                    if (x < 0 || x > this._xsize) return false;
                    xtemp = x;
   
                    // same thing here, to make sure it's not out of the boundaries
                    for (ytemp = y; ytemp > (y - len); ytemp--)
                    {
                        if (ytemp < 0 || ytemp > this._ysize) return false; // oh boho, it was!
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
   
                    // if we're still here, let's start building
                    Corridors++;
                    for (ytemp = y; ytemp > (y - len); ytemp--)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
   
                    break;
   
                case Direction.East:
                    // east
                    if (y < 0 || y > this._ysize) return false;
                    ytemp = y;
   
                    for (xtemp = x; xtemp < (x + len); xtemp++)
                    {
                        if (xtemp < 0 || xtemp > this._xsize) return false;
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
   
                    Corridors++;
                    for (xtemp = x; xtemp < (x + len); xtemp++)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
   
                    break;
   
                case Direction.South:
                    // south
                    if (x < 0 || x > this._xsize) return false;
                    xtemp = x;
                   
                    for (ytemp = y; ytemp < (y + len); ytemp++)
                    {
                        if (ytemp < 0 || ytemp > this._ysize) return false;
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
                   
                    Corridors++;
                    for (ytemp = y; ytemp < (y + len); ytemp++)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
                   
                    break;
                case Direction.West:
                    // west
                    if (ytemp < 0 || ytemp > this._ysize) return false;
                    ytemp = y;
                   
                    for (xtemp = x; xtemp > (x - len); xtemp--)
                    {
                        if (xtemp < 0 || xtemp > this._xsize) return false;
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
                   
                    Corridors++;
                    for (xtemp = x; xtemp > (x - len); xtemp--)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
                   
                    break;
            }


private int xmax = 80; //80 columns
            // woot, we're still here! let's tell the other guys we're done!!
            return true;
        }


private int ymax = 25; //25 rows
        public IEnumerable<Tuple<PointI, Direction>> GetSurroundingPoints(PointI v)
        {
            var points = new[]
                            {
                                Tuple.Create(new PointI { X = v.X, Y = v.Y + 1 }, Direction.North),
                                Tuple.Create(new PointI { X = v.X - 1, Y = v.Y }, Direction.East),
                                Tuple.Create(new PointI { X = v.X , Y = v.Y-1 }, Direction.South),
                                Tuple.Create(new PointI { X = v.X +1, Y = v.Y  }, Direction.West),
                               
                            };
            return points.Where(p => InBounds(p.Item1));
        }


        public IEnumerable<Tuple<PointI, Direction, Tile>> GetSurroundings(PointI v)
        {
            return
                this.GetSurroundingPoints(v)
                    .Select(r => Tuple.Create(r.Item1, r.Item2, this.GetCellType(r.Item1.X, r.Item1.Y)));
        }


        public bool InBounds(int x, int y)
        {
            return x > 0 && x < this.xmax && y > 0 && y < this.ymax;
        }


//size of the map
        public bool InBounds(PointI v)
        {
            return this.InBounds(v.X, v.Y);
        }


private int xsize = 0;
        public bool MakeRoom(int x, int y, int xlength, int ylength, Direction direction)
        {
            // define the dimensions of the room, it should be at least 4x4 tiles (2x2 for walking on, the rest is walls)
            int xlen = this.GetRand(4, xlength);
            int ylen = this.GetRand(4, ylength);


private int ysize = 0;
            // the tile type it's going to be filled with
            const Tile Floor = Tile.DirtFloor;


            const Tile Wall = Tile.DirtWall;
            // choose the way it's pointing at


//number of "objects" to generate on the map
            var points = GetRoomPoints(x, y, xlen, ylen, direction).ToArray();


private int objects = 0;
            // Check if there's enough space left for it
            if (
                points.Any(
                    s =>
                    s.Y < 0 || s.Y > this._ysize || s.X < 0 || s.X > this._xsize || this.GetCellType(s.X, s.Y) != Tile.Unused)) return false;
            _logger(
                      string.Format(
                          "Making room:int x={0}, int y={1}, int xlength={2}, int ylength={3}, int direction={4}",
                          x,
                          y,
                          xlength,
                          ylength,
                          direction));


            foreach (var p in points)
            {
                this.SetCell(p.X, p.Y, IsWall(x, y, xlen, ylen, p.X, p.Y, direction) ? Wall : Floor);
            }


//define the %chance to generate either a room or a corridor on the map
            // yay, all done
//BTW, rooms are 1st priority so actually it's enough to just define the chance
            return true;
//of generating a room
        }


private int chanceRoom = 75;  
        public Tile[] GetDungeon()
        {
            return this._dungeonMap;
        }


private int chanceCorridor = 25;
        public char GetCellTile(int x, int y)
        {
            switch (GetCellType(x, y))
            {
                case Tile.Unused:
                    return '';
                case Tile.DirtWall:
                    return '|';
                case Tile.DirtFloor:
                    return '_';
                case Tile.StoneWall:
                    return 'S';
                case Tile.Corridor:
                    return '#';
                case Tile.Door:
                    return 'D';
                case Tile.Upstairs:
                    return '+';
                case Tile.Downstairs:
                    return '-';
                case Tile.Chest:
                    return 'C';
                default:
                    throw new ArgumentOutOfRangeException("x,y");
            }
        }


        //used to print the map on the screen
        public void ShowDungeon()
        {
            for (int y = 0; y < this._ysize; y++)
            {
                for (int x = 0; x < this._xsize; x++)
                {
                    Console.Write(GetCellTile(x, y));
                }


                if (this._xsize <= xmax) Console.WriteLine();
            }
        }


//our map
        public Direction RandomDirection()
        {
            int dir = this.GetRand(0, 4);
            switch (dir)
            {
                case 0:
                    return Direction.North;
                case 1:
                    return Direction.East;
                case 2:
                    return Direction.South;
                case 3:
                    return Direction.West;
                default:
                    throw new InvalidOperationException();
            }
        }


private int[] dungeon_map = new int[0];
        //and here's the one generating the whole map
        public bool CreateDungeon(int inx, int iny, int inobj)
        {
            this._objects = inobj < 1 ? 10 : inobj;


            // adjust the size of the map, if it's smaller or bigger than the limits
            if (inx < 3) this._xsize = 3;
            else if (inx > xmax) this._xsize = xmax;
            else this._xsize = inx;


//the old seed from the RNG is saved in this one
            if (iny < 3) this._ysize = 3;
            else if (iny > ymax) this._ysize = ymax;
            else this._ysize = iny;


private long oldseed = 0;
            Console.WriteLine(MsgXSize + this._xsize);
            Console.WriteLine(MsgYSize + this._ysize);
            Console.WriteLine(MsgMaxObjects + this._objects);


            // redefine the map var, so it's adjusted to our new map size
            this._dungeonMap = new Tile[this._xsize * this._ysize];


//a list over tile types we're using
            // start with making the "standard stuff" on the map
            this.Initialize();


final private int tileUnused = 0;
            /*******************************************************************************
            And now the code of the random-map-generation-algorithm begins!
            *******************************************************************************/


final private int tileDirtWall = 1; //not in use
            // start with making a room in the middle, which we can start building upon
            this.MakeRoom(this._xsize / 2, this._ysize / 2, 8, 6, RandomDirection()); // getrand saken f????r att slumpa fram riktning p?? rummet


final private int tileDirtFloor = 2;
            // keep count of the number of "objects" we've made
            int currentFeatures = 1; // +1 for the first room we just made


final private int tileStoneWall = 3;
            // then we sart the main loop
            for (int countingTries = 0; countingTries < 1000; countingTries++)
            {
                // check if we've reached our quota
                if (currentFeatures == this._objects)
                {
                    break;
                }


final private int tileCorridor = 4;
                // start with a random wall
                int newx = 0;
                int xmod = 0;
                int newy = 0;
                int ymod = 0;
                Direction? validTile = null;


final private int tileDoor = 5;
                // 1000 chances to find a suitable object (room or corridor)..
                for (int testing = 0; testing < 1000; testing++)
                {
                    newx = this.GetRand(1, this._xsize - 1);
                    newy = this.GetRand(1, this._ysize - 1);


final private int tileUpStairs = 6;
                    if (GetCellType(newx, newy) == Tile.DirtWall || GetCellType(newx, newy) == Tile.Corridor)
                    {
                        var surroundings = this.GetSurroundings(new PointI() { X = newx, Y = newy });


final private int tileDownStairs = 7;
                        // check if we can reach the place
                        var canReach =
                            surroundings.FirstOrDefault(s => s.Item3 == Tile.Corridor || s.Item3 == Tile.DirtFloor);
                        if (canReach == null)
                        {
                            continue;
                        }
                        validTile = canReach.Item2;
                        switch (canReach.Item2)
                        {
                            case Direction.North:
                                xmod = 0;
                                ymod = -1;
                                break;
                            case Direction.East:
                                xmod = 1;
                                ymod = 0;
                                break;
                            case Direction.South:
                                xmod = 0;
                                ymod = 1;
                                break;
                            case Direction.West:
                                xmod = -1;
                                ymod = 0;
                                break;
                            default:
                                throw new InvalidOperationException();
                        }


final private int tileChest = 8;


                        // check that we haven't got another door nearby, so we won't get alot of openings besides
                        // each other


//misc. messages to print
                        if (GetCellType(newx, newy + 1) == Tile.Door) // north
                        {
                            validTile = null;


private String msgXSize = "X size of dungeon: \t";
                        }


private String msgYSize = "Y size of dungeon: \t";
                        else if (GetCellType(newx - 1, newy) == Tile.Door) // east
                            validTile = null;
                        else if (GetCellType(newx, newy - 1) == Tile.Door) // south
                            validTile = null;
                        else if (GetCellType(newx + 1, newy) == Tile.Door) // west
                            validTile = null;
                     


private String msgMaxObjects = "max # of objects: \t";
                        // if we can, jump out of the loop and continue with the rest
                        if (validTile.HasValue) break;
                    }
                }


private String msgNumObjects = "# of objects made: \t";
                if (validTile.HasValue)
                {
                    // choose what to build now at our newly found place, and at what direction
                    int feature = this.GetRand(0, 100);
                    if (feature <= ChanceRoom)
                    { // a new room
                        if (this.MakeRoom(newx + xmod, newy + ymod, 8, 6, validTile.Value))
                        {
                            currentFeatures++; // add to our quota


private String msgHelp = "";
                            // then we mark the wall opening with a door
                            this.SetCell(newx, newy, Tile.Door);


private String msgDetailedHelp = "";
                            // clean up infront of the door so we can reach it
                            this.SetCell(newx + xmod, newy + ymod, Tile.DirtFloor);
                        }
                    }
                    else if (feature >= ChanceRoom)
                    { // new corridor
                        if (this.MakeCorridor(newx + xmod, newy + ymod, 6, validTile.Value))
                        {
                            // same thing here, add to the quota and a door
                            currentFeatures++;


                            this.SetCell(newx, newy, Tile.Door);
                        }
                    }
                }
            }
   
            /*******************************************************************************
            All done with the building, let's finish this one off
            *******************************************************************************/
            AddSprinkles();
   
            // all done with the map generation, tell the user about it and finish
            Console.WriteLine(MsgNumObjects + currentFeatures);
   
            return true;
        }
   
        void Initialize()
        {
            for (int y = 0; y < this._ysize; y++)
            {
                for (int x = 0; x < this._xsize; x++)
                {
                    // ie, making the borders of unwalkable walls
                    if (y == 0 || y == this._ysize - 1 || x == 0 || x == this._xsize - 1)
                    {
                        this.SetCell(x, y, Tile.StoneWall);
                    }
                    else
                    {                        // and fill the rest with dirt
                        this.SetCell(x, y, Tile.Unused);
                    }
                }
            }
        }
   
        // setting a tile's type
        void SetCell(int x, int y, Tile celltype)
        {
            this._dungeonMap[x + this._xsize * y] = celltype;
        }
   
   
      }
    }


</source>




//setting a tile's type
[[Category:Developing]]
 
private void setCell(int x, int y, int celltype){
 
dungeon_map[x + xsize * y] = celltype;
 
}
 
 
//returns the type of a tile
 
private int getCell(int x, int y){
 
return dungeon_map[x + xsize * y];
 
}
 
 
//The RNG. the seed is based on seconds from the "java epoch" ( I think..)
//perhaps it's the same date as the unix epoch
 
private int getRand(int min, int max){
 
//the seed is based on current date and the old, already used seed
Date now = new Date();
 
long seed = now.getTime() + oldseed;
 
oldseed = seed;
 
 
Random randomizer = new Random(seed);
 
int n = max - min + 1;
 
int i = randomizer.nextInt() % n;
 
if (i < 0)
 
i = -i;
 
//System.out.println("seed: " + seed + "\tnum:  " + (min + i));
 
return min + i;
 
}
 
 
private boolean makeCorridor(int x, int y, int lenght, int direction){
 
//define the dimensions of the corridor (er.. only the width and height..)
 
int len = getRand(2, lenght);
 
int floor = tileCorridor;
 
int dir = 0;
 
if (direction > 0 && direction < 4) dir = direction;
 
int xtemp = 0;
 
int ytemp = 0;
 
 
switch(dir){
 
case 0:
 
//north
 
//check if there's enough space for the corridor
//start with checking it's not out of the boundaries
 
if (x < 0 || x > xsize) return false;
 
else xtemp = x;
 
//same thing here, to make sure it's not out of the boundaries
 
for (ytemp = y; ytemp > (y-len); ytemp--){
 
if (ytemp < 0 || ytemp > ysize) return false; //oh boho, it was!
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
 
//if we're still here, let's start building
 
for (ytemp = y; ytemp > (y-len); ytemp--){
 
setCell(xtemp, ytemp, floor);
 
}
 
break;
 
case 1:
 
//east
 
if (y < 0 || y > ysize) return false;
 
else ytemp = y;
 
 
for (xtemp = x; xtemp < (x+len); xtemp++){
 
if (xtemp < 0 || xtemp > xsize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
 
for (xtemp = x; xtemp < (x+len); xtemp++){
 
setCell(xtemp, ytemp, floor);
 
}
 
break;
 
case 2:
 
//south
 
if (x < 0 || x > xsize) return false;
 
else xtemp = x;
 
 
for (ytemp = y; ytemp < (y+len); ytemp++){
 
if (ytemp < 0 || ytemp > ysize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
 
for (ytemp = y; ytemp < (y+len); ytemp++){
 
setCell(xtemp, ytemp, floor);
 
}
 
break;
 
case 3:
 
//west
 
if (ytemp < 0 || ytemp > ysize) return false;
 
else ytemp = y;
 
 
for (xtemp = x; xtemp > (x-len); xtemp--){
 
if (xtemp < 0 || xtemp > xsize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
 
for (xtemp = x; xtemp > (x-len); xtemp--){
 
setCell(xtemp, ytemp, floor);
 
}
 
break;
 
}
 
 
//woot, we're still here! let's tell the other guys we're done!!
 
return true;
 
}
 
 
private boolean makeRoom(int x, int y, int xlength, int ylength, int direction){
 
//define the dimensions of the room, it should be at least 4x4 tiles (2x2 for walking on, the rest is walls)
 
int xlen = getRand(4, xlength);
 
int ylen = getRand(4, ylength);
 
//the tile type it's going to be filled with
 
int floor = tileDirtFloor; //jordgolv..
 
int wall = tileDirtWall; //jordv????gg
 
//choose the way it's pointing at
 
int dir = 0;
 
if (direction > 0 && direction < 4) dir = direction;
 
 
 
switch(dir){
 
case 0:
 
//north
 
//Check if there's enough space left for it
 
for (int ytemp = y; ytemp > (y-ylen); ytemp--){
 
if (ytemp < 0 || ytemp > ysize) return false;
 
for (int xtemp = (x-xlen/2); xtemp < (x+(xlen+1)/2); xtemp++){
 
if (xtemp < 0 || xtemp > xsize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false; //no space left...
 
}
 
}
 
 
//we're still here, build
 
for (int ytemp = y; ytemp > (y-ylen); ytemp--){
 
for (int xtemp = (x-xlen/2); xtemp < (x+(xlen+1)/2); xtemp++){
 
//start with the walls
 
if (xtemp == (x-xlen/2)) setCell(xtemp, ytemp, wall);
 
else if (xtemp == (x+(xlen-1)/2)) setCell(xtemp, ytemp, wall);
 
else if (ytemp == y) setCell(xtemp, ytemp, wall);
 
else if (ytemp == (y-ylen+1)) setCell(xtemp, ytemp, wall);
 
//and then fill with the floor
 
else setCell(xtemp, ytemp, floor);
 
}
 
}
 
break;
 
case 1:
 
//east
 
for (int ytemp = (y-ylen/2); ytemp < (y+(ylen+1)/2); ytemp++){
 
if (ytemp < 0 || ytemp > ysize) return false;
 
for (int xtemp = x; xtemp < (x+xlen); xtemp++){
 
if (xtemp < 0 || xtemp > xsize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
}
 
 
 
for (int ytemp = (y-ylen/2); ytemp < (y+(ylen+1)/2); ytemp++){
 
for (int xtemp = x; xtemp < (x+xlen); xtemp++){
 
 
if (xtemp == x) setCell(xtemp, ytemp, wall);
 
else if (xtemp == (x+xlen-1)) setCell(xtemp, ytemp, wall);
 
else if (ytemp == (y-ylen/2)) setCell(xtemp, ytemp, wall);
 
else if (ytemp == (y+(ylen-1)/2)) setCell(xtemp, ytemp, wall);
 
 
else setCell(xtemp, ytemp, floor);
 
}
 
}
 
break;
 
case 2:
 
//south
 
for (int ytemp = y; ytemp < (y+ylen); ytemp++){
 
if (ytemp < 0 || ytemp > ysize) return false;
 
for (int xtemp = (x-xlen/2); xtemp < (x+(xlen+1)/2); xtemp++){
 
if (xtemp < 0 || xtemp > xsize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
}
 
 
for (int ytemp = y; ytemp < (y+ylen); ytemp++){
 
for (int xtemp = (x-xlen/2); xtemp < (x+(xlen+1)/2); xtemp++){
 
 
if (xtemp == (x-xlen/2)) setCell(xtemp, ytemp, wall);
 
else if (xtemp == (x+(xlen-1)/2)) setCell(xtemp, ytemp, wall);
 
else if (ytemp == y) setCell(xtemp, ytemp, wall);
 
else if (ytemp == (y+ylen-1)) setCell(xtemp, ytemp, wall);
 
 
else setCell(xtemp, ytemp, floor);
 
}
 
}
 
break;
 
case 3:
 
//west
 
for (int ytemp = (y-ylen/2); ytemp < (y+(ylen+1)/2); ytemp++){
 
if (ytemp < 0 || ytemp > ysize) return false;
 
for (int xtemp = x; xtemp > (x-xlen); xtemp--){
 
if (xtemp < 0 || xtemp > xsize) return false;
 
if (getCell(xtemp, ytemp) != tileUnused) return false;
 
}
 
}
 
 
for (int ytemp = (y-ylen/2); ytemp < (y+(ylen+1)/2); ytemp++){
 
for (int xtemp = x; xtemp > (x-xlen); xtemp--){
 
 
if (xtemp == x) setCell(xtemp, ytemp, wall);
 
else if (xtemp == (x-xlen+1)) setCell(xtemp, ytemp, wall);
 
else if (ytemp == (y-ylen/2)) setCell(xtemp, ytemp, wall);
 
else if (ytemp == (y+(ylen-1)/2)) setCell(xtemp, ytemp, wall);
 
 
else setCell(xtemp, ytemp, floor);
 
}
 
}
 
break;
 
}
 
 
//yay, all done
 
return true;
 
}
 
 
 
//used to print the map on the screen
 
public void showDungeon(){
 
for (int y = 0; y < ysize; y++){
 
for (int x = 0; x < xsize; x++){
 
//System.out.print(getCell(x, y));
 
switch(getCell(x, y)){
 
case tileUnused:
 
System.out.print(" ");
 
break;
 
case tileDirtWall:
 
System.out.print("+");
 
break;
 
case tileDirtFloor:
 
System.out.print(".");
 
break;
 
case tileStoneWall:
 
System.out.print("O");
 
break;
 
case tileCorridor:
 
System.out.print("#");
 
break;
 
case tileDoor:
 
System.out.print("D");
 
break;
 
case tileUpStairs:
 
System.out.print("<");
 
break;
 
case tileDownStairs:
 
System.out.print(">");
 
break;
 
case tileChest:
 
System.out.print("*");
 
break;
 
};
 
}
 
if (xsize < xmax) System.out.print("\n");
 
}
 
}
 
 
//and here's the one generating the whole map
 
public boolean createDungeon(int inx, int iny, int inobj){
 
if (inobj < 1) objects = 10;
 
else objects = inobj;
 
 
//justera kartans storlek, om den ????r st????rre eller mindre ????n "gr????nserna"
//adjust the size of the map, if it's smaller or bigger than the limits
 
if (inx < 3) xsize = 3;
 
else if (inx > xmax) xsize = xmax;
 
else xsize = inx;
 
 
if (iny < 3) ysize = 3;
 
else if (iny > ymax) ysize = ymax;
 
else ysize = iny;
 
 
System.out.println(msgXSize + xsize);
 
System.out.println(msgYSize + ysize);
 
System.out.println(msgMaxObjects + objects);
 
 
//redefine the map var, so it's adjusted to our new map size
 
dungeon_map = new int[xsize * ysize];
 
 
//start with making the "standard stuff" on the map
 
for (int y = 0; y < ysize; y++){
 
for (int x = 0; x < xsize; x++){
 
//ie, making the borders of unwalkable walls
 
if (y == 0) setCell(x, y, tileStoneWall);
 
else if (y == ysize-1) setCell(x, y, tileStoneWall);
 
else if (x == 0) setCell(x, y, tileStoneWall);
 
else if (x == xsize-1) setCell(x, y, tileStoneWall);
 
 
//and fill the rest with dirt
 
else setCell(x, y, tileUnused);
 
}
 
}
 
 
/*******************************************************************************
 
And now the code of the random-map-generation-algorithm begins!
 
*******************************************************************************/
 
 
//start with making a room in the middle, which we can start building upon
 
makeRoom(xsize/2, ysize/2, 8, 6, getRand(0,3)); //getrand saken f????r att slumpa fram riktning p?? rummet
 
 
//keep count of the number of "objects" we've made
 
int currentFeatures = 1; //+1 for the first room we just made
 
 
//then we sart the main loop
 
for (int countingTries = 0; countingTries < 1000; countingTries++){
 
//check if we've reached our quota
 
if (currentFeatures == objects){
 
break;
 
}
 
 
//start with a random wall
 
int newx = 0;
 
int xmod = 0;
 
int newy = 0;
 
int ymod = 0;
 
int validTile = -1;
 
//1000 chances to find a suitable object (room or corridor)..
//(yea, i know it's kinda ugly with a for-loop... -_-')
 
for (int testing = 0; testing < 1000; testing++){
 
newx = getRand(1, xsize-1);
 
newy = getRand(1, ysize-1);
 
validTile = -1;
 
//System.out.println("tempx: " + newx + "\ttempy: " + newy);
 
if (getCell(newx, newy) == tileDirtWall || getCell(newx, newy) == tileCorridor){
 
//check if we can reach the place
 
if (getCell(newx, newy+1) == tileDirtFloor || getCell(newx, newy+1) == tileCorridor){
 
validTile = 0; //
 
xmod = 0;
 
ymod = -1;
 
}
 
else if (getCell(newx-1, newy) == tileDirtFloor || getCell(newx-1, newy) == tileCorridor){
 
validTile = 1; //
 
xmod = +1;
 
ymod = 0;
 
}
 
else if (getCell(newx, newy-1) == tileDirtFloor || getCell(newx, newy-1) == tileCorridor){
 
validTile = 2; //
 
xmod = 0;
 
ymod = +1;
 
}
 
else if (getCell(newx+1, newy) == tileDirtFloor || getCell(newx+1, newy) == tileCorridor){
 
validTile = 3; //
 
xmod = -1;
 
ymod = 0;
 
}
 
 
//check that we haven't got another door nearby, so we won't get alot of openings besides
//each other
 
if (validTile > -1){
 
if (getCell(newx, newy+1) == tileDoor) //north
 
validTile = -1;
 
else if (getCell(newx-1, newy) == tileDoor)//east
 
validTile = -1;
 
else if (getCell(newx, newy-1) == tileDoor)//south
 
validTile = -1;
 
else if (getCell(newx+1, newy) == tileDoor)//west
 
validTile = -1;
 
}
 
 
//if we can, jump out of the loop and continue with the rest
 
if (validTile > -1) break;
 
}
 
}
 
if (validTile > -1){
 
//choose what to build now at our newly found place, and at what direction
 
int feature = getRand(0, 100);
 
if (feature <= chanceRoom){ //a new room
 
if (makeRoom((newx+xmod), (newy+ymod), 8, 6, validTile)){
 
currentFeatures++; //add to our quota
 
 
//then we mark the wall opening with a door
 
setCell(newx, newy, tileDoor);
 
 
//clean up infront of the door so we can reach it
 
setCell((newx+xmod), (newy+ymod), tileDirtFloor);
 
}
 
}
 
else if (feature >= chanceRoom){ //new corridor
 
if (makeCorridor((newx+xmod), (newy+ymod), 6, validTile)){
 
//same thing here, add to the quota and a door
 
currentFeatures++;
 
 
setCell(newx, newy, tileDoor);
 
}
 
}
 
}
 
}
 
 
 
/*******************************************************************************
 
All done with the building, let's finish this one off
 
*******************************************************************************/
 
 
//sprinkle out the bonusstuff (stairs, chests etc.) over the map
 
int newx = 0;
 
int newy = 0;
 
int ways = 0; //from how many directions we can reach the random spot from
 
int state = 0; //the state the loop is in, start with the stairs
 
while (state != 10){
 
for (int testing = 0; testing < 1000; testing++){
 
newx = getRand(1, xsize-1);
 
newy = getRand(1, ysize-2); //cheap bugfix, pulls down newy to 0<y<24, from 0<y<25
 
 
 
//System.out.println("x: " + newx + "\ty: " + newy);
 
ways = 4; //the lower the better
 
 
//check if we can reach the spot
 
if (getCell(newx, newy+1) == tileDirtFloor || getCell(newx, newy+1) == tileCorridor){
 
//north
 
if (getCell(newx, newy+1) != tileDoor)
 
ways--;
 
}
 
if (getCell(newx-1, newy) == tileDirtFloor || getCell(newx-1, newy) == tileCorridor){
 
//east
 
if (getCell(newx-1, newy) != tileDoor)
 
ways--;
 
}
 
if (getCell(newx, newy-1) == tileDirtFloor || getCell(newx, newy-1) == tileCorridor){
 
//south
 
if (getCell(newx, newy-1) != tileDoor)
 
ways--;
 
}
 
if (getCell(newx+1, newy) == tileDirtFloor || getCell(newx+1, newy) == tileCorridor){
 
//west
 
if (getCell(newx+1, newy) != tileDoor)
 
ways--;
 
}
 
 
if (state == 0){
 
if (ways == 0){
 
//we're in state 0, let's place a "upstairs" thing
 
setCell(newx, newy, tileUpStairs);
 
state = 1;
 
break;
 
}
 
}
 
else if (state == 1){
 
if (ways == 0){
 
//state 1, place a "downstairs"
 
setCell(newx, newy, tileDownStairs);
 
state = 10;
 
break;
 
}
 
}
 
}
 
}
 
 
 
//all done with the map generation, tell the user about it and finish
 
System.out.println(msgNumObjects + currentFeatures);
 
 
return true;
 
}
 
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
public static void main(String[] args){
 
//initial stuff used in making the map
 
int x = 80; int y = 25; int dungeon_objects = 0;
 
 
//convert a string to a int, if there's more then one arg
 
if (args.length >= 1)
 
dungeon_objects = Integer.parseInt(args[0]);
 
 
 
if (args.length >= 2)
 
x = Integer.parseInt(args[1]);
 
 
if (args.length >= 3)
 
y = Integer.parseInt(args[2]);
 
 
 
//create a new class of "dungen", so we can use all the goodies within it
 
dungen generator = new dungen();
 
 
//then we create a new dungeon map
 
if (generator.createDungeon(x, y, dungeon_objects)){
 
//always good to be able to see the results..
 
generator.showDungeon();
 
}
 
}
 
}
</pre>
 
</small>

Latest revision as of 09:02, 2 June 2016

(Made by Solarnus)

This code is C#, not Java


     public class Dungeon
      {
    
        // misc. messages to print
        const string MsgXSize = "X size of dungeon: \t";
    
        const string MsgYSize = "Y size of dungeon: \t";
    
        const string MsgMaxObjects = "max # of objects: \t";
    
        const string MsgNumObjects = "# of objects made: \t";
    
        // max size of the map
        int xmax = 80; //columns
        int ymax = 25; //rows
    
        // size of the map
        int _xsize;
        int _ysize;
    
        // number of "objects" to generate on the map
        int _objects;
    
        // define the %chance to generate either a room or a corridor on the map
        // BTW, rooms are 1st priority so actually it's enough to just define the chance
        // of generating a room
        const int ChanceRoom = 75;
    
        // our map
        Tile[] _dungeonMap = { };
    
        readonly IRandomize _rnd;
    
        readonly Action<string> _logger;
    
    
        public Dungeon(IRandomize rnd, Action<string> logger)
        {
            _rnd = rnd;
            _logger = logger;
        }
        
        public int Corridors
        {
            get;
            private set;
        }
    
        public static bool IsWall(int x, int y, int xlen, int ylen, int xt, int yt, Direction d)
        {
            Func<int, int, int> a = GetFeatureLowerBound;
            
            Func<int, int, int> b = IsFeatureWallBound;
            switch (d)
            {
                case Direction.North:
                    return xt == a(x, xlen) || xt == b(x, xlen) || yt == y || yt == y - ylen + 1;
                case Direction.East:
                    return xt == x || xt == x + xlen - 1 || yt == a(y, ylen) || yt == b(y, ylen);
                case Direction.South:
                    return xt == a(x, xlen) || xt == b(x, xlen) || yt == y || yt == y + ylen - 1;
                case Direction.West:
                    return xt == x || xt == x - xlen + 1 || yt == a(y, ylen) || yt == b(y, ylen);
            }
            
            throw new InvalidOperationException();
        }
    
        public static int GetFeatureLowerBound(int c, int len)
        {
            return c - len / 2;
        }
    
        public static int IsFeatureWallBound(int c, int len)
        {
            return c + (len - 1) / 2;
        }
    
        public static int GetFeatureUpperBound(int c, int len)
        {
            return c + (len + 1) / 2;
        }
    
        public static IEnumerable<PointI> GetRoomPoints(int x, int y, int xlen, int ylen, Direction d)
        {
            // north and south share the same x strategy
            // east and west share the same y strategy
            Func<int, int, int> a = GetFeatureLowerBound;
            Func<int, int, int> b = GetFeatureUpperBound;
    
            switch (d)
            {
                case Direction.North:
                    for (var xt = a(x, xlen); xt < b(x, xlen); xt++) for (var yt = y; yt > y - ylen; yt--) yield return new PointI { X = xt, Y = yt };
                    break;
                case Direction.East:
                    for (var xt = x; xt < x + xlen; xt++) for (var yt = a(y, ylen); yt < b(y, ylen); yt++) yield return new PointI { X = xt, Y = yt };
                    break;
                case Direction.South:
                    for (var xt = a(x, xlen); xt < b(x, xlen); xt++) for (var yt = y; yt < y + ylen; yt++) yield return new PointI { X = xt, Y = yt };
                    break;
                case Direction.West:
                    for (var xt = x; xt > x - xlen; xt--) for (var yt = a(y, ylen); yt < b(y, ylen); yt++) yield return new PointI { X = xt, Y = yt };
                    break;
                default:
                    yield break;
            }
        }
    
        public Tile GetCellType(int x, int y)
        {
            try
            {
                return this._dungeonMap[x + this._xsize * y];
            }
            catch (IndexOutOfRangeException)
            {
                new { x, y }.Dump("exceptional");
                throw;
            }
        }
    
        public int GetRand(int min, int max)
        {
            return _rnd.Next(min, max);
        }
    
        public bool MakeCorridor(int x, int y, int length, Direction direction)
        {
            // define the dimensions of the corridor (er.. only the width and height..)
            int len = this.GetRand(2, length);
            const Tile Floor = Tile.Corridor;
    
            int xtemp;
            int ytemp = 0;
    
            switch (direction)
            {
                case Direction.North:
                    // north
                    // check if there's enough space for the corridor
                    // start with checking it's not out of the boundaries
                    if (x < 0 || x > this._xsize) return false;
                    xtemp = x;
    
                    // same thing here, to make sure it's not out of the boundaries
                    for (ytemp = y; ytemp > (y - len); ytemp--)
                    {
                        if (ytemp < 0 || ytemp > this._ysize) return false; // oh boho, it was!
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
    
                    // if we're still here, let's start building
                    Corridors++;
                    for (ytemp = y; ytemp > (y - len); ytemp--)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
    
                    break;
    
                case Direction.East:
                    // east
                    if (y < 0 || y > this._ysize) return false;
                    ytemp = y;
    
                    for (xtemp = x; xtemp < (x + len); xtemp++)
                    {
                        if (xtemp < 0 || xtemp > this._xsize) return false;
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
    
                    Corridors++;
                    for (xtemp = x; xtemp < (x + len); xtemp++)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
    
                    break;
    
                case Direction.South:
                    // south
                    if (x < 0 || x > this._xsize) return false;
                    xtemp = x;
                    
                    for (ytemp = y; ytemp < (y + len); ytemp++)
                    {
                        if (ytemp < 0 || ytemp > this._ysize) return false;
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
                    
                    Corridors++;
                    for (ytemp = y; ytemp < (y + len); ytemp++)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
                    
                    break;
                case Direction.West:
                    // west
                    if (ytemp < 0 || ytemp > this._ysize) return false;
                    ytemp = y;
                    
                    for (xtemp = x; xtemp > (x - len); xtemp--)
                    {
                        if (xtemp < 0 || xtemp > this._xsize) return false;
                        if (GetCellType(xtemp, ytemp) != Tile.Unused) return false;
                    }
                    
                    Corridors++;
                    for (xtemp = x; xtemp > (x - len); xtemp--)
                    {
                        this.SetCell(xtemp, ytemp, Floor);
                    }
                    
                    break;
            }

            // woot, we're still here! let's tell the other guys we're done!!
            return true;
        }

        public IEnumerable<Tuple<PointI, Direction>> GetSurroundingPoints(PointI v)
        {
            var points = new[]
                             {
                                 Tuple.Create(new PointI { X = v.X, Y = v.Y + 1 }, Direction.North),
                                 Tuple.Create(new PointI { X = v.X - 1, Y = v.Y }, Direction.East),
                                 Tuple.Create(new PointI { X = v.X , Y = v.Y-1 }, Direction.South),
                                 Tuple.Create(new PointI { X = v.X +1, Y = v.Y  }, Direction.West),
                                 
                             };
            return points.Where(p => InBounds(p.Item1));
        }

        public IEnumerable<Tuple<PointI, Direction, Tile>> GetSurroundings(PointI v)
        {
            return
                this.GetSurroundingPoints(v)
                    .Select(r => Tuple.Create(r.Item1, r.Item2, this.GetCellType(r.Item1.X, r.Item1.Y)));
        }

        public bool InBounds(int x, int y)
        {
            return x > 0 && x < this.xmax && y > 0 && y < this.ymax;
        }

        public bool InBounds(PointI v)
        {
            return this.InBounds(v.X, v.Y);
        }

        public bool MakeRoom(int x, int y, int xlength, int ylength, Direction direction)
        {
            // define the dimensions of the room, it should be at least 4x4 tiles (2x2 for walking on, the rest is walls)
            int xlen = this.GetRand(4, xlength);
            int ylen = this.GetRand(4, ylength);

            // the tile type it's going to be filled with
            const Tile Floor = Tile.DirtFloor;

            const Tile Wall = Tile.DirtWall;
            // choose the way it's pointing at

            var points = GetRoomPoints(x, y, xlen, ylen, direction).ToArray();

            // Check if there's enough space left for it
            if (
                points.Any(
                    s =>
                    s.Y < 0 || s.Y > this._ysize || s.X < 0 || s.X > this._xsize || this.GetCellType(s.X, s.Y) != Tile.Unused)) return false;
            _logger(
                      string.Format(
                          "Making room:int x={0}, int y={1}, int xlength={2}, int ylength={3}, int direction={4}",
                          x,
                          y,
                          xlength,
                          ylength,
                          direction));

            foreach (var p in points)
            {
                this.SetCell(p.X, p.Y, IsWall(x, y, xlen, ylen, p.X, p.Y, direction) ? Wall : Floor);
            }

            // yay, all done
            return true;
        }

        public Tile[] GetDungeon()
        {
            return this._dungeonMap;
        }

        public char GetCellTile(int x, int y)
        {
            switch (GetCellType(x, y))
            {
                case Tile.Unused:
                    return '';
                case Tile.DirtWall:
                    return '|';
                case Tile.DirtFloor:
                    return '_';
                case Tile.StoneWall:
                    return 'S';
                case Tile.Corridor:
                    return '#';
                case Tile.Door:
                    return 'D';
                case Tile.Upstairs:
                    return '+';
                case Tile.Downstairs:
                    return '-';
                case Tile.Chest:
                    return 'C';
                default:
                    throw new ArgumentOutOfRangeException("x,y");
            }
        }

        //used to print the map on the screen
        public void ShowDungeon()
        {
            for (int y = 0; y < this._ysize; y++)
            {
                for (int x = 0; x < this._xsize; x++)
                {
                    Console.Write(GetCellTile(x, y));
                }

                if (this._xsize <= xmax) Console.WriteLine();
            }
        }

        public Direction RandomDirection()
        {
            int dir = this.GetRand(0, 4);
            switch (dir)
            {
                case 0:
                    return Direction.North;
                case 1:
                    return Direction.East;
                case 2:
                    return Direction.South;
                case 3:
                    return Direction.West;
                default:
                    throw new InvalidOperationException();
            }
        }

        //and here's the one generating the whole map
        public bool CreateDungeon(int inx, int iny, int inobj)
        {
            this._objects = inobj < 1 ? 10 : inobj;

            // adjust the size of the map, if it's smaller or bigger than the limits
            if (inx < 3) this._xsize = 3;
            else if (inx > xmax) this._xsize = xmax;
            else this._xsize = inx;

            if (iny < 3) this._ysize = 3;
            else if (iny > ymax) this._ysize = ymax;
            else this._ysize = iny;

            Console.WriteLine(MsgXSize + this._xsize);
            Console.WriteLine(MsgYSize + this._ysize);
            Console.WriteLine(MsgMaxObjects + this._objects);

            // redefine the map var, so it's adjusted to our new map size
            this._dungeonMap = new Tile[this._xsize * this._ysize];

            // start with making the "standard stuff" on the map
            this.Initialize();

            /*******************************************************************************
            And now the code of the random-map-generation-algorithm begins!
            *******************************************************************************/

            // start with making a room in the middle, which we can start building upon
            this.MakeRoom(this._xsize / 2, this._ysize / 2, 8, 6, RandomDirection()); // getrand saken f????r att slumpa fram riktning p?? rummet

            // keep count of the number of "objects" we've made
            int currentFeatures = 1; // +1 for the first room we just made

            // then we sart the main loop
            for (int countingTries = 0; countingTries < 1000; countingTries++)
            {
                // check if we've reached our quota
                if (currentFeatures == this._objects)
                {
                    break;
                }

                // start with a random wall
                int newx = 0;
                int xmod = 0;
                int newy = 0;
                int ymod = 0;
                Direction? validTile = null;

                // 1000 chances to find a suitable object (room or corridor)..
                for (int testing = 0; testing < 1000; testing++)
                {
                    newx = this.GetRand(1, this._xsize - 1);
                    newy = this.GetRand(1, this._ysize - 1);

                    if (GetCellType(newx, newy) == Tile.DirtWall || GetCellType(newx, newy) == Tile.Corridor)
                    {
                        var surroundings = this.GetSurroundings(new PointI() { X = newx, Y = newy });

                        // check if we can reach the place
                        var canReach =
                            surroundings.FirstOrDefault(s => s.Item3 == Tile.Corridor || s.Item3 == Tile.DirtFloor);
                        if (canReach == null)
                        {
                            continue;
                        }
                        validTile = canReach.Item2;
                        switch (canReach.Item2)
                        {
                            case Direction.North:
                                xmod = 0;
                                ymod = -1;
                                break;
                            case Direction.East:
                                xmod = 1;
                                ymod = 0;
                                break;
                            case Direction.South:
                                xmod = 0;
                                ymod = 1;
                                break;
                            case Direction.West:
                                xmod = -1;
                                ymod = 0;
                                break;
                            default:
                                throw new InvalidOperationException();
                        }


                        // check that we haven't got another door nearby, so we won't get alot of openings besides
                        // each other

                        if (GetCellType(newx, newy + 1) == Tile.Door) // north
                        {
                            validTile = null;

                        }

                        else if (GetCellType(newx - 1, newy) == Tile.Door) // east
                            validTile = null;
                        else if (GetCellType(newx, newy - 1) == Tile.Door) // south
                            validTile = null;
                        else if (GetCellType(newx + 1, newy) == Tile.Door) // west
                            validTile = null;
                       

                        // if we can, jump out of the loop and continue with the rest
                        if (validTile.HasValue) break;
                    }
                }

                if (validTile.HasValue)
                {
                    // choose what to build now at our newly found place, and at what direction
                    int feature = this.GetRand(0, 100);
                    if (feature <= ChanceRoom)
                    { // a new room
                        if (this.MakeRoom(newx + xmod, newy + ymod, 8, 6, validTile.Value))
                        {
                            currentFeatures++; // add to our quota

                            // then we mark the wall opening with a door
                            this.SetCell(newx, newy, Tile.Door);

                            // clean up infront of the door so we can reach it
                            this.SetCell(newx + xmod, newy + ymod, Tile.DirtFloor);
                        }
                    }
                    else if (feature >= ChanceRoom)
                    { // new corridor
                        if (this.MakeCorridor(newx + xmod, newy + ymod, 6, validTile.Value))
                        {
                            // same thing here, add to the quota and a door
                            currentFeatures++;

                            this.SetCell(newx, newy, Tile.Door);
                        }
                    }
                }
            }
    
            /*******************************************************************************
            All done with the building, let's finish this one off
            *******************************************************************************/
            AddSprinkles();
    
            // all done with the map generation, tell the user about it and finish
            Console.WriteLine(MsgNumObjects + currentFeatures);
    
            return true;
        }
    
        void Initialize()
        {
            for (int y = 0; y < this._ysize; y++)
            {
                for (int x = 0; x < this._xsize; x++)
                {
                    // ie, making the borders of unwalkable walls
                    if (y == 0 || y == this._ysize - 1 || x == 0 || x == this._xsize - 1)
                    {
                        this.SetCell(x, y, Tile.StoneWall);
                    }
                    else
                    {                        // and fill the rest with dirt
                        this.SetCell(x, y, Tile.Unused);
                    }
                }
            }
        }
    
        // setting a tile's type
        void SetCell(int x, int y, Tile celltype)
        {
            this._dungeonMap[x + this._xsize * y] = celltype;
        }
    
    
      }
    }