<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Dimi Chakarov</title>
    <description>The latest articles on Forem by Dimi Chakarov (@dchakarov).</description>
    <link>https://forem.com/dchakarov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F70801%2F4bba474a-05b9-4522-913b-6bea3ee93657.jpeg</url>
      <title>Forem: Dimi Chakarov</title>
      <link>https://forem.com/dchakarov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dchakarov"/>
    <language>en</language>
    <item>
      <title>From Algorithms to Adventures</title>
      <dc:creator>Dimi Chakarov</dc:creator>
      <pubDate>Sat, 13 Dec 2025 12:56:55 +0000</pubDate>
      <link>https://forem.com/dchakarov/from-algorithms-to-adventures-1ffk</link>
      <guid>https://forem.com/dchakarov/from-algorithms-to-adventures-1ffk</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/dchakarov/from-ruby-to-swift-building-a-maze-generation-framework-4ccj"&gt;previous post&lt;/a&gt;, I shared the story of how I fell in love with maze algorithms. I wrote about porting Jamis Buck’s Ruby code to Swift, building a visualisation engine, and the intellectual joy of understanding "perfect" mazes.&lt;/p&gt;

&lt;p&gt;I ended that project with a robust &lt;code&gt;MazeGenerator&lt;/code&gt; framework and a technical demo. I felt like 90% of the work was done. I just needed to wrap some UI around it, add a "Start" button, and I’d have a game.&lt;/p&gt;

&lt;p&gt;I was wrong. I had a simulation, not a game. And turning the former into the latter would take me on a journey through bad design decisions, harsh feedback, and a complete pivot in how I thought about "fun."&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Nerd" Trap (v1.0)
&lt;/h2&gt;

&lt;p&gt;When you build a game engine before you build a game, you tend to value the wrong things. I was obsessed with the algorithms. I wanted players to appreciate the difference between the &lt;strong&gt;Recursive Backtracker&lt;/strong&gt; (long, winding rivers) and &lt;strong&gt;Prim’s Algorithm&lt;/strong&gt; (short, organic branches).&lt;/p&gt;

&lt;p&gt;My first version of the game was essentially my tech demo with added controls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Core Loop:&lt;/strong&gt; Select an algorithm, generate a maze, solve it, and try not to touch any walls as you get points deducted for that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Cool" Feature:&lt;/strong&gt; A "Draw Mode" where you could sketch a shape with your finger, and the framework would generate a maze around it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Educational Angle:&lt;/strong&gt; Info screens explaining "Diagonal Bias" and "Spanning Trees."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I thought it was brilliant. It wasn’t. It was boring.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Reality Check
&lt;/h3&gt;

&lt;p&gt;You can’t convince people to use your app or play your game if you don’t do it yourself. I installed the game on my phone and tried to play it instead of Balatro or Mini Motorways. I didn’t last one hour. There wasn’t anything to keep me entertained or to make me want to win more points. I was bored.&lt;/p&gt;

&lt;p&gt;Also, the "Draw Mode"? It turns out that drawing a mask with your fat finger on a phone screen results in a blocky, ugly shape. It was a technical marvel that resulted in a terrible user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the Fun
&lt;/h2&gt;

&lt;p&gt;I was three months in. The codebase was sprawling with features nobody cared about (algorithm selectors, learning tabs, map editors). I had a choice to make: release a tech demo that no one would play, or strip back the nerdy features and make the game fun.&lt;/p&gt;

&lt;p&gt;I chose the latter.&lt;/p&gt;

&lt;p&gt;I stripped out the algorithm selector. I hid the educational content. I removed the Draw screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Move Limit
&lt;/h3&gt;

&lt;p&gt;The breakthrough came when I stopped punishing the player for hitting a wall and introduced a &lt;strong&gt;Move-Based&lt;/strong&gt; system.&lt;/p&gt;

&lt;p&gt;In the new version, you are given a strict budget of moves to solve the maze.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency matters:&lt;/strong&gt; You can't just wander; you have to plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fairness is guaranteed:&lt;/strong&gt; For any specific maze seed, the optimal path is a fixed number of steps. I could calculate the "Perfect Score" mathematically using Dijkstra's algorithm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tension:&lt;/strong&gt; Running out of moves is far more stressful (in a good way) than a timer counting up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suddenly, it wasn't a racing game anymore. It was a strategy game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the "Game" Part
&lt;/h2&gt;

&lt;p&gt;Once I had the core mechanic, I needed to wrap it in a progression system. A game needs to feel like a journey, not a loop.&lt;/p&gt;

&lt;p&gt;I introduced:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Power-ups:&lt;/strong&gt; Since moves are vital to the game, power-ups became about economy. "Demolish Wall" costs coins to buy, but can help you get to that hidden crate and back before you run out of moves. "Jump" lets you skip long corridors and cash in on any remaining moves you have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terrain:&lt;/strong&gt; I added ice (you slide, saving moves but losing control) and mud (costs double moves).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progression:&lt;/strong&gt; I added progressively harder levels - the mazes get bigger, the crates are further from the happy path, the terrain is rocky. Every ten levels, you get a prize. Every now and then, you unlock a rare avatar or stumble upon a hidden gem.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Tech Stack: SwiftUI
&lt;/h3&gt;

&lt;p&gt;I built the entire game in &lt;strong&gt;SwiftUI&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Many developers warned me against this, suggesting SpriteKit or Unity. But for a grid-based puzzle game, SwiftUI is surprisingly capable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State Management:&lt;/strong&gt; The grid is composed of &lt;code&gt;VStacks&lt;/code&gt; and &lt;code&gt;HStacks&lt;/code&gt;, rendered based on the game state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animations:&lt;/strong&gt; SwiftUI's implicit animations made the player movement (sliding from tile to tile) buttery smooth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterative Speed:&lt;/strong&gt; I could change the "Mud" tile view in one file and see it update across the entire game instantly in the Preview.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hardest part was positioning the “items” and the player layers on top of the maze layer. I ended up using a complex layering of &lt;code&gt;ZStacks&lt;/code&gt; that I don't recommend to the faint of heart, but it worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launching
&lt;/h2&gt;

&lt;p&gt;The game, &lt;strong&gt;MZ: Maze Adventures&lt;/strong&gt;, is finished. &lt;/p&gt;

&lt;p&gt;All the cute avatars in the game were designed by my wife; the not-so-cute ones - by me. The music was composed by my son (who also decided to download the game to play, not just to listen to his music in action). It has no algorithm selectors, no "Draw Mode," and no educational lectures.&lt;/p&gt;

&lt;p&gt;It just has mazes. Perfect, frustrating, beautiful mazes.&lt;/p&gt;

&lt;p&gt;You can download it now on the App Store.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/mz-maze-adventures/id6746577798" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakg681m37maqzhk4poq9.png" width="498" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>iosdev</category>
      <category>gamedev</category>
      <category>puzzles</category>
      <category>swift</category>
    </item>
    <item>
      <title>From Ruby to Swift - Building a Maze Generation Framework</title>
      <dc:creator>Dimi Chakarov</dc:creator>
      <pubDate>Sun, 09 Nov 2025 16:35:23 +0000</pubDate>
      <link>https://forem.com/dchakarov/from-ruby-to-swift-building-a-maze-generation-framework-4ccj</link>
      <guid>https://forem.com/dchakarov/from-ruby-to-swift-building-a-maze-generation-framework-4ccj</guid>
      <description>&lt;p&gt;I wasn't looking for a game idea when I picked up &lt;strong&gt;Mazes for Programmers&lt;/strong&gt; by Jamis Buck. I was just curious about algorithms and looking for something different from the usual data structures textbooks. And the book gave me that - it was incredibly well-written. I couldn't stop reading. But there was one problem: all the code examples were in Ruby.&lt;/p&gt;

&lt;p&gt;Ruby is not exactly my cup of tea. As an iOS developer, I am familiar with it, but I never got fluent. But I was itching for a new project, and I wanted to truly understand these algorithms, not just copy code in a language I didn't know. So I embraced the challenge and started converting the code to Swift. What began as a simple translation exercise eventually evolved into a full Swift framework, then a demo app, and ultimately became an iOS game called MZ: Maze Adventures.&lt;/p&gt;

&lt;p&gt;This is the story of that journey - specifically, the technical foundation that made everything else possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes Maze Algorithms Fascinating
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, let me share what captured my imagination about maze algorithms. They don't just generate mazes; they generate &lt;strong&gt;perfect mazes&lt;/strong&gt;. In graph theory terms, a perfect maze is a spanning tree of all cells in the grid. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The maze is connected (you can reach any cell from any other cell)&lt;/li&gt;
&lt;li&gt;It's acyclic (no loops)&lt;/li&gt;
&lt;li&gt;It has exactly V-1 edges for V vertices&lt;/li&gt;
&lt;li&gt;Most importantly: there's exactly one path between any two cells&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here's where it gets interesting: different algorithms produce mazes with vastly different characteristics, almost like different "personalities."&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Algorithms, Three Personalities
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Recursive Backtracker (Depth-First Search)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This algorithm explores as far as possible before backtracking, creating long, winding corridors with fewer branches. The result is what's called a "river pattern": paths that players can get trapped in for extended exploration. It has high complexity and is ideal for more challenging puzzles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prim's Algorithm (Randomised)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Prim's randomly expands from the growing maze, creating many short dead ends with a tree-like structure. It feels more organic and natural, offering frequent decision points for the player. The complexity is medium, with many branching choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Binary Tree&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Each cell makes a binary choice (typically north or east), resulting in a strong diagonal bias and predictable texture. Its main benefit? It's very fast to generate. The downside is that the bias makes solutions easier to find. You can often solve these mazes by following the long corridors on the top or right edges.&lt;/p&gt;

&lt;p&gt;For MZ: Maze Adventures, I ultimately chose Recursive Backtracker because I liked how the long corridors looked, and the higher complexity made it more challenging for players.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Ruby to Swift Translation Challenge
&lt;/h2&gt;

&lt;p&gt;When I began translating the algorithms, I had to consider every detail carefully. Ruby and Swift are fundamentally different languages with different paradigms, and that meant more than just syntax changes.&lt;/p&gt;

&lt;p&gt;Here's a side-by-side comparison of the Recursive Backtracker algorithm:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ruby (from the book):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecursiveBacktracker&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;start_at: &lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="n"&gt;start_at&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
      &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;
      &lt;span class="n"&gt;neighbors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;neighbors&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
        &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;neighbor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;grid&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Swift (my framework):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;RecursiveBacktrackerMazeGenerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MazeGenerating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generateStep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;generated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;evaluating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;])?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;unvisitedNeighbours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;neighbours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;unvisitedNeighbours&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popLast&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;neighbour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
              &lt;span class="n"&gt;unvisitedNeighbours&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomElement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
            &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cell1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cell2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;neighbour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;generated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                &lt;span class="nv"&gt;evaluating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logic is identical - both use a stack to track visited cells, both explore neighbours, and both backtrack when stuck. But the differences reveal each language's philosophy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby's &lt;code&gt;neighbors.sample&lt;/code&gt; is elegant and expressive&lt;/li&gt;
&lt;li&gt;Swift requires &lt;code&gt;randomElement()!&lt;/code&gt; with explicit unwrapping&lt;/li&gt;
&lt;li&gt;Ruby uses class methods (&lt;code&gt;def self.on&lt;/code&gt;), while I used instance methods&lt;/li&gt;
&lt;li&gt;Swift's type safety means more explicit handling of optionals&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Beyond One-to-One Translation
&lt;/h3&gt;

&lt;p&gt;Initially, I translated the algorithms one-to-one. But then I wanted to visualise the generation of mazes step by step, not all at once. This forced me to restructure the code - instead of generating a complete maze in one pass, I needed a &lt;code&gt;generateStep()&lt;/code&gt; method that returned intermediate states.&lt;/p&gt;

&lt;p&gt;For three of the twelve algorithms I translated, I abandoned the Ruby code completely and implemented them based purely on the algorithm descriptions in the book. By that point, I understood the patterns well enough that it was actually easier than getting stuck in translation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a Framework, Not Just Code
&lt;/h2&gt;

&lt;p&gt;The real insight came when I decided to build this as a proper Swift framework rather than just a collection of files. This decision paid massive dividends later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protocol-Oriented Design
&lt;/h3&gt;

&lt;p&gt;At the core of the framework is the &lt;code&gt;MazeGenerating&lt;/code&gt; protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;MazeGenerating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generateMaze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generateStep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;generated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;evaluating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;])?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple protocol allowed for easy swapping of algorithms. Need a different maze style? Just change the algorithm. Want to compare algorithms visually? Iterate through them. The flexibility was incredible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Design Principles
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Principle 1: Separation of Concerns&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Grid&lt;/code&gt; handles cell structure and topology&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Cell&lt;/code&gt; manages individual cell state and links&lt;/li&gt;
&lt;li&gt;Algorithms implement &lt;code&gt;MazeGenerating&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Solvers (like Dijkstra's) work on any valid maze&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Principle 2: Type Safety Prevents Errors&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can't link cells from different grids&lt;/li&gt;
&lt;li&gt;Can't access out-of-bounds cells&lt;/li&gt;
&lt;li&gt;Can't create invalid maze states&lt;/li&gt;
&lt;li&gt;Swift's type system catches these at compile time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Principle 3: Reference Semantics with Observable State for Real-Time Visualisation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Observable&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cell1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cell2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cell1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cell2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cell2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cell1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// Changes automatically notify SwiftUI views&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;@Observable&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Cell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Cell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this design choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grid and cells are classes because they're mutated during maze generation&lt;/li&gt;
&lt;li&gt;The algorithm modifies the grid in place; changes happen instantly&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Observable&lt;/code&gt; allows SwiftUI views to automatically redraw as cells are linked&lt;/li&gt;
&lt;li&gt;In the demo app, watching the maze generate step-by-step in real time was only possible because SwiftUI could react to these observable state changes&lt;/li&gt;
&lt;li&gt;The visualisation loop becomes trivial: algorithm mutates observable grid → SwiftUI redraws → user sees generation in progress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The power of this approach: Separating the generative algorithm from UI concerns through &lt;code&gt;@Observable&lt;/code&gt; meant the demo app didn't need complex bindings or manual refresh logic. SwiftUI's reactive framework automatically handled the visualisation.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Framework to Demo App
&lt;/h2&gt;

&lt;p&gt;In order to see what I was generating - and this will sound very familiar to iOS developers - I added a demo app to the framework. The demo app was written in SwiftUI and imported the framework.&lt;/p&gt;

&lt;p&gt;The demo app lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select different maze generation algorithms&lt;/li&gt;
&lt;li&gt;Generate mazes with a button press&lt;/li&gt;
&lt;li&gt;Visualise the maze structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, I added a solver using Dijkstra’s algorithm to show the optimal paths through the maze. Watching the solver trace the perfect path through a Recursive Backtracker maze was mesmerising.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Aha" Moment
&lt;/h3&gt;

&lt;p&gt;Even before finishing the book, I was already thinking: &lt;strong&gt;This could be a game, right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once I could visualise these mazes and watch the solver find optimal paths, the game idea crystallised. Players could attempt to solve mazes with a limited number of moves. The solver could calculate fair move limits. Power-ups could let players bend the rules.&lt;/p&gt;

&lt;p&gt;The framework was no longer just a learning project. It was the foundation for something playable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Framework Separation Pays Off
&lt;/h3&gt;

&lt;p&gt;Building a separate framework compelled me to consider interfaces and contracts. When I later built the game, I could import the framework and immediately have working maze generation - no copy-pasting, no coupling. The framework could be tested independently, and game logic stayed cleanly separated from maze generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Translation Forces Deep Understanding
&lt;/h3&gt;

&lt;p&gt;Translating the Ruby algorithms to Swift made me understand them far more deeply than if I'd just read the Ruby code. I had to think about data structures, error handling, performance, and architecture. Every design decision was intentional, not just inherited from the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualisation Changes Everything
&lt;/h3&gt;

&lt;p&gt;The demo app wasn't just a nice-to-have; it fundamentally changed how I understood the algorithms. Seeing the mazes generate, watching the solver work, experimenting with parameters - this hands-on interaction revealed insights I would never have gained from code alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start Simple, Iterate Quickly
&lt;/h3&gt;

&lt;p&gt;The framework started with just three algorithms and basic functionality. But because the design was sound (thank you, protocol-oriented programming), I added eight more algorithms over time. Each took 30-60 minutes to implement with no changes to existing code.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;This framework became the foundation for &lt;a href="https://testflight.apple.com/join/seMEPPhP" rel="noopener noreferrer"&gt;MZ: Maze Adventures&lt;/a&gt;, an iOS game that's currently in beta testing. In future articles, I'll dive into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building the game layer on top of the framework&lt;/li&gt;
&lt;li&gt;SwiftUI for game development (pros and cons)&lt;/li&gt;
&lt;li&gt;Progression, power-ups, and game economy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it all started here: with a curious developer, a Ruby book, and the decision to translate algorithms into Swift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to explore maze generation yourself?&lt;/strong&gt; &lt;a href="https://github.com/swiftyaf/MazeAlgorithms" rel="noopener noreferrer"&gt;The framework is open-source on GitHub&lt;/a&gt;. Start with the Recursive Backtracker - it's the most rewarding to watch in action. Or if you are into Ruby, I can recommend a great book! Find it here: &lt;a href="https://pragprog.com/titles/jbmaze/mazes-for-programmers/" rel="noopener noreferrer"&gt;Mazes for Programmers&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>algorithms</category>
      <category>iosdev</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
