Creating Brogue-like in Swift: Bringing a Classic Roguelike to iOS

Classic roguelikes have always fascinated me. Among them, Brogue stands out for its elegant design: simple controls, deep emergent gameplay, and beautifully readable ASCII graphics.

However, the original Brogue codebase is written in C and designed primarily for desktop environments. I wanted to explore what it would look like if the game were rebuilt from the ground up in Swift, optimized for touchscreens and modern iOS devices.

This project is not a direct port. Instead, it is a full reimplementation, preserving the spirit of Brogue while modernizing its architecture.


Why Reimplementation Instead of Port?

Porting C code to iOS is possible, but it often results in:

A reimplementation allows:

The goal was to keep gameplay behavior LIKE where it matters, while modernizing everything else.


Goals of the Project

The reimplementation focuses on several principles:

1. Preserve Gameplay

The core mechanics remain faithful:

The design philosophy of Brogue—simple rules producing complex outcomes—remains intact.


2. Modern Architecture

The original codebase is heavily procedural. In Swift, the game is organized into clear modules:

Core systems include:

Swift’s enums, structs, and OptionSets make these systems significantly safer and clearer.

Example:

struct CreatureType: Codable {
    var monsterName: String
    var maxHP: Int
    var defense: Int
    var accuracy: Int
    var damage: RandomRange
}

Compared to the original C structs, Swift models provide:


Rebuilding the Grid System

Brogue’s dungeon operates on a grid of tiles.

In the Swift reimplementation, the map uses a generic grid structure:

struct Grid2D<Element> {
    let cols: Int
    let rows: Int
    var data: [Element]

    subscript(x: Int, y: Int) -> Element {
        get { data[x * rows + y] }
        set { data[x * rows + y] = newValue }
    }
}

This abstraction allows:

to all share the same efficient storage.


Deterministic Randomness

Roguelikes rely on deterministic RNG to ensure reproducibility.

The Swift version uses a custom RNG implementation.

This guarantees:

    /// Core PCG32 output (32-bit).
    mutating func nextUInt32() -> UInt32 {
        let old = state
        // LCG step
        state = old &* 6364136223846793005 &+ inc
        
        // Output function XSH RR
        let xorshifted = UInt32(truncatingIfNeeded: ((old >> 18) ^ old) >> 27)
        let rot = UInt32(truncatingIfNeeded: old >> 59)
        return (xorshifted >> rot) | (xorshifted << ((0 &- rot) & 31))
    }

Dungeon Generation

One of Brogue’s most elegant systems is its dungeon generation pipeline.

Each level goes through several stages:

  1. layout generation
  2. terrain carving
  3. room connection
  4. feature placement
  5. item spawning
  6. monster spawning

The reimplementation keeps this pipeline but modularizes it so each stage is easier to test and tweak.


Combat and Emergent Gameplay

Combat in Brogue is intentionally simple:

Yet the interaction between:

creates deep tactical gameplay.

The reimplementation preserves these interactions while cleaning up the combat engine.


Touch-Friendly Controls

A major goal of the reimplementation is making the game comfortable on a phone screen.

Key design choices include:

Classic roguelikes were designed for keyboards. The Swift version is designed for touch first.


Performance Considerations

Although Swift is high-level, performance is still critical.

Several strategies help keep the game fast:

The result runs smoothly even on older iPhones.


Asset and Rendering Pipeline

Instead of ASCII characters, the iOS version uses minimal pixel tiles designed for readability.

Each tile is rendered on a 96×96 canvas, optimized for small screens.

This keeps the spirit of the original game while improving visual clarity.


Challenges During the Reimplementation

Several parts of the original codebase required special attention:

Dungeon Feature System

Brogue uses a complex feature system for traps, gas, fire, and environmental effects. Implementing these systems required careful restructuring to avoid deeply nested procedural code.


Monster AI

Monster behavior combines:

Implementing this logic while preserving gameplay behavior required extensive testing.


Emergent Item Interactions

Many interesting interactions arise from combinations like:

These behaviors had to be preserved exactly to maintain the game’s identity.


Why Swift Works Well for Roguelikes

Swift turned out to be an excellent language for this project.

Advantages include:

These features make game logic easier to reason about compared to C.


Current Status

The reimplementation now includes:

The game plays like classic Brogue, but runs natively on iOS.


Final Thoughts

Reimplementing a classic game engine is a large project, but it provides an opportunity to deeply understand the original design.

Brogue remains one of the most elegant roguelikes ever created, and rebuilding it in Swift has been both challenging and rewarding.

The goal of this project is not to replace the original, but to explore how a timeless design can evolve on modern platforms.


If you're interested in roguelikes, procedural generation, or Swift game development, I hope this project inspires you to experiment with your own engine.