Skip to content

Instantly share code, notes, and snippets.

@Hammer2900
Created May 18, 2025 13:41
Show Gist options
  • Save Hammer2900/499ef1dfcde3161c522f9c6d6cd626ee to your computer and use it in GitHub Desktop.
Save Hammer2900/499ef1dfcde3161c522f9c6d6cd626ee to your computer and use it in GitHub Desktop.
procedural dungeon generator using random walk in lobster
import vec
import color
import gl
import std
let screen_width = 800
let screen_height = 600
let tile_size = 20
let map_width = screen_width / tile_size
let map_height = screen_height / tile_size
enum TileType:
WALL
FLOOR
class OptionalInt2Pos:
pos: int2
class Dungeon:
width: int
height: int
tiles: [[TileType]]
floor_tiles: [int2]
def create_dungeon(width: int, height: int) -> Dungeon:
let initial_tiles = mapxy(int2 { width, height }) v: WALL
let initial_floor_tiles = []
return Dungeon { width, height, initial_tiles, initial_floor_tiles }
def add_floor_tile(dungeon::Dungeon, pos: int2):
if pos.x >= 0 and pos.x < dungeon.width and pos.y >= 0 and pos.y < dungeon.height:
dungeon.tiles[pos.y][pos.x] = FLOOR
dungeon.floor_tiles.push(pos)
def create_room(dungeon::Dungeon, center_x: int, center_y: int, size: int) -> void:
let half_size = size / 2
for_range_incl(center_y - half_size, center_y + half_size) y:
for_range_incl(center_x - half_size, center_x + half_size) x:
if x > 0 and x < dungeon.width - 1 and y > 0 and y < dungeon.height - 1:
add_floor_tile(dungeon, int2 { x, y })
def add_random_rooms(dungeon::Dungeon, room_chance: float = 0.1) -> void:
let floor_tiles_copy = copy(dungeon.floor_tiles)
for (floor_tiles_copy) tile_pos:
if rnd_float() < room_chance:
let room_size = rnd(3) + 2
create_room(dungeon, tile_pos.x, tile_pos.y, room_size)
def generate_dungeon(dungeon::Dungeon, num_steps: int, start_pos_opt: OptionalInt2Pos?) -> Dungeon:
var current_pos = if start_pos_opt != nil:
assert start_pos_opt
start_pos_opt.pos
else:
int2 { dungeon.width / 2, dungeon.height / 2 }
add_floor_tile(dungeon, current_pos)
for num_steps:
let dx = rnd(3) - 1
let dy = rnd(3) - 1
let new_pos_candidate = current_pos + int2 { dx, dy }
current_pos.x = clamp(new_pos_candidate.x, 1, dungeon.width - 2)
current_pos.y = clamp(new_pos_candidate.y, 1, dungeon.height - 2)
add_floor_tile(dungeon, current_pos)
add_random_rooms()
return dungeon
fatal(gl.window("Random Walk Dungeon Generator", screen_width, screen_height))
gl.set_target_delta_time(1.0 / 60.0)
var font_loaded = gl.set_font_name("data/fonts/Droid_Sans/DroidSans.ttf")
if not font_loaded: font_loaded = gl.set_font_name("C:/Windows/Fonts/arial.ttf")
if not font_loaded: print "Warning: Font not loaded, text will not be visible."
rnd_seed(int(seconds_elapsed() * 1000100.0))
var dungeon = create_dungeon(map_width, map_height)
var should_regenerate = true
while gl.frame() and gl.button("escape") != 1:
if gl.button("space") == 1:
should_regenerate = true
if should_regenerate:
dungeon = create_dungeon(map_width, map_height)
generate_dungeon(dungeon, 1000, nil)
// generate_dungeon(dungeon, 1000, OptionalInt2Pos { int2 { 10, 10 } })
should_regenerate = false
gl.ortho(false, false)
gl.clear(color_black)
for (dungeon.height) y:
for (dungeon.width) x:
let pos_on_screen = float(int2 { x, y } * tile_size)
if dungeon.tiles[y][x] == FLOOR:
gl.color(color_grey)
gl.translate(pos_on_screen):
gl.rect(float2_1 * tile_size)
gl.line_mode(1)
gl.color(color_dark_grey)
gl.translate(pos_on_screen):
gl.rect(float2_1 * tile_size)
gl.line_mode(0)
if font_loaded:
gl.set_font_size(20)
gl.color(color_white)
gl.translate(float2 { 10.0, 10.0 }):
gl.text("Press SPACE to regenerate")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment