Skip to content

Instantly share code, notes, and snippets.

@donarb
Created March 5, 2019 21:54
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 donarb/1502a12cb16fa74f4fd2e295867da253 to your computer and use it in GitHub Desktop.
Save donarb/1502a12cb16fa74f4fd2e295867da253 to your computer and use it in GitHub Desktop.
Swift playground implementation of random dungeon generator
// ported from https://gist.github.com/munificent/b1bcd969063da3e6c298be070a22b604
//
// can be run in a Swift playground
import Cocoa
let HEIGHT = 40
let WIDTH = 80
var FIELD: [[Character]] = Array(repeating: Array(repeating: " ", count: WIDTH), count: HEIGHT)
let tileVoid: Character = " "
let tileFloor: Character = "."
let tileWall: Character = "#"
let tileCorner: Character = "!"
let tileOpenDoor: Character = "\\"
let tileClosedDoor: Character = "+"
let tilePlayer: Character = "@"
// cave()
func cave(withPlayer: Bool) {
// width, height, left and top are all inner
// dimensions/coordinates (w/o walls)
let width = Int.random(in: 5..<15)
let height = Int.random(in: 3..<9)
let left = Int.random(in: 0..<WIDTH-width-2) + 1
let top = Int.random(in: 0..<HEIGHT-height-2) + 1
// Check if the new cave (with walls) intersects with the interior of
// any already existing cave. Touching walls/corners are okay
for y in top-1..<top+height+2 {
for x in left-1..<left+width+2 {
guard FIELD[y][x] != tileFloor else { return }
}
}
// Find a suitable place for a door
var doorCounter = 0
var doorX, doorY: Int?
if !withPlayer {
for y in top-1..<top+height+2 {
for x in left-1..<left+width+2 {
let atVerticalWall = x < left || x > left + width
let atHorizontalWall = y < top || y > top + height
let atWallButNotAtCorner = atVerticalWall != atHorizontalWall
// The door should not be created in the cave's corner or over
// another door, or in another cave's corner. It's impossible
// to make a cave without a door, because randInt(1) always
// returns 0.
if atWallButNotAtCorner && FIELD[y][x] == tileWall {
doorCounter += 1
if Int.random(in: 0..<doorCounter) == 0 {
doorX = x
doorY = y
}
}
}
}
// If the cave's walls were made completely out of corners
// and doors, don't make such a cave
guard doorCounter > 0 else { return }
}
// The cave looks ok, let's draw it
for y in top-1..<top+height+2 {
for x in left-1..<left+width+2 {
let atVerticalWall = x < left || x > left + width
let atHorizontalWall = y < top || y > top + height
let atCorner = atVerticalWall && atHorizontalWall
let atWallButNotAtCorner = atVerticalWall != atHorizontalWall
// We need to somehow record corners of all caves to check
// for intersections later, so we use a special tile for it
FIELD[y][x] = atCorner ? tileCorner : (atWallButNotAtCorner ? tileWall : tileFloor)
}
// Now draw the door. The test is redundant, btw, because
// of "if (doorCounter == 0) { return; } earlier
if doorCounter > 0 {
if let dy = doorY, let dx = doorX {
FIELD[dy][dx] = Bool.random() ? tileOpenDoor : tileClosedDoor
}
}
if withPlayer {
// A cave with a player has only the player inside it
FIELD[Int.random(in: 0..<height) + top][Int.random(in: 0..<width) + left] = tilePlayer
} else {
// A cave without a player
let mob = "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz~"
for _ in 1..<Int.random(in: 1..<7) {
let idx = Int.random(in: 0..<mob.count)
let range = mob.index(mob.startIndex, offsetBy: idx)..<mob.index(mob.startIndex, offsetBy: idx+1)
FIELD[Int.random(in: 0..<height)+top][Int.random(in: 0..<width)+left] =
Int.random(in: 0..<4) == 0 ? "$" : Character(String(mob[range]))
}
}
}
}
// main()
// Fill in the field with the void
for y in 0..<HEIGHT {
for x in 0..<WIDTH {
FIELD[y][x] = tileVoid
}
}
// A call to cave() is not guranteed to actually make a new cave,
// so call it many times
for j in 0..<1_000 {
cave(withPlayer: j == 0)
}
// Print the generated field
for y in 0..<HEIGHT {
for x in 0..<WIDTH {
let c = FIELD[y][x]
// The cave corners should be drawn as walls
print(c == tileCorner ? tileWall : c, separator: "", terminator: "")
if x == WIDTH - 1 {
print("")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment