<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Thomas Seeley - algos</title><id>https://www.tseeley.com/tags/algos/atom.xml</id><updated>2024-08-22T00:00:00+00:00</updated><generator>tseeley.com</generator><link href="https://www.tseeley.com/tags/algos/atom.xml" rel="self" type="application/atom+xml"/><link href="https://www.tseeley.com" rel="alternate" type="text/html"/><subtitle>Posts about software and making things.</subtitle><entry><title>Maze Playground</title><id>https://www.tseeley.com/posts/maze-playground/</id><updated>2024-08-22T00:00:00+00:00</updated><author><name>Thomas Seeley</name></author><link href="https://www.tseeley.com/posts/maze-playground/" rel="alternate" type="text/html"/><published>2024-08-22T00:00:00+00:00</published><content type="html">
&lt;p&gt;I read Andrew Healey’s &lt;a href=&quot;https://healeycodes.com/generating-mazes&quot;&gt;Generating Mazes&lt;/a&gt; and wanted to see the algorithms work. Not just the finished maze, but each step of the generation. Walls getting removed one at a time, the path carving through the grid.&lt;/p&gt;
&lt;p&gt;So I built a &lt;a href=&quot;https://github.com/iamseeley/maze-playground&quot;&gt;small playground&lt;/a&gt; for it. Deno, TypeScript, and a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;section id=&quot;The-Data-Model&quot;&gt;
&lt;h2&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#The-Data-Model&quot;&gt;The Data Model&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A maze is a grid of cells. Each cell has four walls and knows whether it’s been visited.&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span style=&quot;color:#888888;&quot;&gt;export &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;class Cell implements CellInterface &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;{
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;Position&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  hasTopWall&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  hasRightWall&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  hasBottomWall&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  hasLeftWall&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  visited&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  removeWall&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;neighbor: CellInterface&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;void {
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    const dx = neighbor.position.x - this.position.x;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    const dy = neighbor.position.y - this.position.y;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(dx === &lt;/span&gt;&lt;span style=&quot;color:#e0c020;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;) {
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;this.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;hasRightWall &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#e0c020;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      neighbor&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;hasLeftWall &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#e0c020;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;font-style:italic;color:#666666;&quot;&gt;// ... and so on for each direction
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}
&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;removeWall&lt;/code&gt; figures out which direction the neighbor is in and removes the wall on both sides. That’s the core operation of maze generation: two cells become connected.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Generators-for-Stepping&quot;&gt;
&lt;h2&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#Generators-for-Stepping&quot;&gt;Generators for Stepping&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The part I liked most was using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_generators&quot;&gt;JavaScript generators&lt;/a&gt; for the algorithms. DFS yields after each step, which means the UI can consume it at whatever pace it wants.&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span style=&quot;color:#888888;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;generateSteps&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;maze: MazeInterface&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;startCell: CellInterface&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;: Generator&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;&amp;lt;{ &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;currentCell&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;CellInterface &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}&amp;gt; {
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  const stack&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;CellInterface&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;[] = [&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;startCell&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  startCell.visited = true;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;while &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(stack&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt; &amp;gt; 0&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;) {
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;const &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;currentCell &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;stack&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;stack&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color:#e0c020;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;];
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;yield { &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;currentCell &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;};
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;const &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;unvisitedNeighbors &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;maze&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;getNeighbors&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;currentCell&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;)
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(neighbor =&amp;gt; !&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;neighbor&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;visited&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;);
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;if (&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;unvisitedNeighbors&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;length &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#e0c020;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;) {
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;const &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;randomIndex &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;() * &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;unvisitedNeighbors&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;);
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;const &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;chosenNeighbor &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;unvisitedNeighbors&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;randomIndex&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;];
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      currentCell&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;removeWall&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;chosenNeighbor&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;);
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      chosenNeighbor&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;visited &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color:#e0c020;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;;
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      stack&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;chosenNeighbor&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;);
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;} else {
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;      stack&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;font-weight:bold;color:#eeeeee;&quot;&gt;pop&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;();
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}
&lt;/span&gt;&lt;span style=&quot;color:#e2e2e5;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}
&lt;/span&gt;&lt;span style=&quot;color:#888888;&quot;&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The UI runs a &lt;code&gt;setInterval&lt;/code&gt; at 50ms that calls &lt;code&gt;generator.next()&lt;/code&gt;, snapshots the maze state, and renders it. After generation is done, a slider lets you scrub back through every step. You can watch the algorithm think.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Whats-There-Whats-Not&quot;&gt;
&lt;h2&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#Whats-There-Whats-Not&quot;&gt;What’s There, What’s Not&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Right now only &lt;a href=&quot;https://en.wikipedia.org/wiki/Depth-first_search&quot;&gt;DFS&lt;/a&gt; is implemented. The dropdown lists &lt;a href=&quot;https://en.wikipedia.org/wiki/Maze_generation_algorithm#Aldous-Broder_algorithm&quot;&gt;Aldous-Broder&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_Prim&apos;s_algorithm&quot;&gt;Prim’s&lt;/a&gt;, and &lt;a href=&quot;https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_Kruskal&apos;s_algorithm&quot;&gt;Kruskal’s&lt;/a&gt; but they’re stubs. I’d like to add them eventually because the interesting thing about maze algorithms is how different the mazes &lt;em&gt;feel&lt;/em&gt;. DFS creates long winding corridors with few branches. Aldous-Broder creates more uniform, random-looking mazes. Same grid, different character.&lt;/p&gt;
&lt;p&gt;The rendering is simple Canvas drawing. Visited cells get a gray fill, the current cell gets a blue highlight, and walls are just lines. Nothing fancy, but it’s enough to see what’s happening.&lt;/p&gt;
&lt;/section&gt;

&lt;hr&gt;
&lt;p&gt;&lt;code&gt;typescript&lt;/code&gt; &lt;code&gt;algos&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tseeley.com/about/&quot;&gt;Thomas Seeley&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bsky.app/profile/tseeley.com&quot;&gt;@tseeley.com on Bluesky&lt;/a&gt;, &lt;a href=&quot;https://mastodon.social/@iamseeley&quot;&gt;@iamseeley on Mastodon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;larr; &lt;a href=&quot;https://www.tseeley.com/posts/hello-membrane/&quot;&gt;Hello, Membrane&lt;/a&gt; · &lt;a href=&quot;https://www.tseeley.com/posts/schemeing/&quot;&gt;Scheme-ing&lt;/a&gt; &amp;rarr;&lt;/p&gt;
</content></entry></feed>