<?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: John Merchant</title>
    <description>The latest articles on Forem by John Merchant (@johnmerchant).</description>
    <link>https://forem.com/johnmerchant</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%2F186441%2F574218f7-289b-485d-8c1f-42058f2643c4.jpeg</url>
      <title>Forem: John Merchant</title>
      <link>https://forem.com/johnmerchant</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/johnmerchant"/>
    <language>en</language>
    <item>
      <title>Conway's Game of Life - with friends!</title>
      <dc:creator>John Merchant</dc:creator>
      <pubDate>Fri, 30 Aug 2019 17:16:16 +0000</pubDate>
      <link>https://forem.com/johnmerchant/conway-s-game-of-life-with-friends-3jj9</link>
      <guid>https://forem.com/johnmerchant/conway-s-game-of-life-with-friends-3jj9</guid>
      <description>&lt;p&gt;This is the story of how I created something cool and amusing, using computers, electronics, code, creativity and curiosity. The end result being &lt;a href="https://www.multilife.jmercha.dev/"&gt;https://www.multilife.jmercha.dev/&lt;/a&gt; &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/johnmerchant"&gt;
        johnmerchant
      &lt;/a&gt; / &lt;a href="https://github.com/johnmerchant/multilife"&gt;
        multilife
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Multiplayer Game of Life cellular automata simulation
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
MultiLife.live&lt;/h1&gt;
&lt;p&gt;An experiment in realtime cellular automata.&lt;/p&gt;
&lt;p&gt;See my &lt;a href="https://dev.to/jmercha/conway-s-game-of-life-with-friends-3jj9" rel="nofollow"&gt;DEV Community&lt;/a&gt; post for the story behind this.&lt;/p&gt;
&lt;p&gt;Basically, an interactive multiplayer digital lava lamp.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/ecb197d94e10a4ed9ff3efab4038cacb2257b0fd8298003e4fc5c11fe0f26e1c/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f524a744a4152624959506a756f42725832322f67697068792e676966"&gt;&lt;img src="https://camo.githubusercontent.com/ecb197d94e10a4ed9ff3efab4038cacb2257b0fd8298003e4fc5c11fe0f26e1c/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f524a744a4152624959506a756f42725832322f67697068792e676966" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
MultiLife RGB&lt;/h2&gt;
&lt;p&gt;MutliLife can rendered to an RGB LED matrix panel using a Raspberry Pi with &lt;a href="https://github.com/jmercha/multilife-rgb"&gt;multilife-rgb&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Dependencies&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 13&lt;/li&gt;
&lt;li&gt;yarn&lt;/li&gt;
&lt;li&gt;A computer with an operating system.&lt;/li&gt;
&lt;li&gt;Or alternatively, Docker&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Design&lt;/h2&gt;
&lt;p&gt;The frontend is implemented in React, using Redux to manage the client-side state.&lt;/p&gt;
&lt;p&gt;The game itself is rendered using a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Game state is managed server side, and events are pushed live between clients and the server using a websocket&lt;/p&gt;
&lt;p&gt;The protocol, models and utility functions are all &lt;a href="https://en.wikipedia.org/wiki/Isomorphic_JavaScript" rel="nofollow"&gt;isomorphic&lt;/a&gt;. That is to say, it is code able to be executed on both the server and client side.&lt;/p&gt;
&lt;h2&gt;
Running&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;yarn dev-server&lt;/code&gt; - builds and starts the server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yarn dev-client&lt;/code&gt; - builds and starts the frontend&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/johnmerchant/multilife"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Origins
&lt;/h2&gt;

&lt;p&gt;I was talking to a few friends and colleagues recently about &lt;a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"&gt;Conway's Game of Life&lt;/a&gt;. It can be basically explained as follows. &lt;/p&gt;

&lt;p&gt;There is a grid of cells with 2 states: alive and dead. On each iteration of the game there are a set of rules which are evaluated on each cell on the grid:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Live cells with &amp;lt; 3 live neighbors die&lt;/li&gt;
&lt;li&gt;Live cells with &amp;gt; 1 live neighbors live on to the next iteration&lt;/li&gt;
&lt;li&gt;Live cells with &amp;gt; 3 neighbors die&lt;/li&gt;
&lt;li&gt;Dead cells with exactly 3 neighbors become alive&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Back in the 2000's, I had created a Game of Life Java Applet that ran in the browser - Applets being long since deprecated and the original source code unfortunately lost to time. I had a lot of fun writing it and showing it off to people.&lt;/p&gt;

&lt;p&gt;I started to think to myself, could I do it again in 2019 using my favorite web technologies? Could I performantly render a dynamic grid of cells in JSX? How would the game state be represented and updated? &lt;/p&gt;

&lt;p&gt;I ended up going down multiple rabbit holes and tangents and ended up learning a lot!&lt;/p&gt;

&lt;h2&gt;
  
  
  Experimentation
&lt;/h2&gt;

&lt;p&gt;In the initial iterations of my experiment, I attempted to render the the grid as a sequence of JSX elements. &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements with '⬜' (white box) emoji to represent living cells and '⬛' (black box) to represent dead cells. As those familiar with React may know, this wasn't a great idea: the DOM is excruciatingly slow to update, even with React's &lt;a href="https://reactjs.org/docs/reconciliation.html"&gt;reconciliation&lt;/a&gt;, it was still updating hundreds of DOM elements on each tick, resulting in an unresponsive experience. e.g. a cell click event would take almost 100ms to update the entire grid.&lt;/p&gt;

&lt;p&gt;So, how could I performantly render the game of life grid then? The answer is, with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"&gt;&amp;lt;canvas&amp;gt;&lt;/a&gt;. I used React's &lt;a href="https://reactjs.org/docs/hooks-effect.html"&gt;useEffect&lt;/a&gt; hook to paint the game state on each state update to the canvas element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiplayer
&lt;/h2&gt;

&lt;p&gt;I started to think about where to store and handle the game state and decided to manage the game state in Redux so I could clearly define and handle game events using actions and reducers. To put it as simply as possible, Redux is a "state container" that allows you to reduce the events (a.k.a actions) raised by your application into a single, predictable state. &lt;/p&gt;

&lt;p&gt;While I was implementing the reducers and actions I thought: wouldn't it be really easy to centralize the game state and broadcast to multiple "players"? I then moved all of the game processing logic: the game update interval, rule evaluation and player events into a Node.js server, hooked up some web socket actions and thus "multilife" was created.&lt;/p&gt;

&lt;p&gt;Although there are existing frameworks for using WebSockets with Redux, e.g. &lt;a href="https://github.com/giantmachines/redux-websocket"&gt;redux-websocket&lt;/a&gt;, I decided to write my own, as there are only 4 simple actions required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WS_OPEN&lt;/code&gt; - connection open&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WS_SEND&lt;/code&gt; - send a message to the server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WS_RECEIVE&lt;/code&gt;- receive a message from the server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WS_CLOSE&lt;/code&gt; - connection closed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also needed more control over the format I sent and received messages in, using binary instead of JSON, as I describe in the Optimization section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Colors
&lt;/h2&gt;

&lt;p&gt;Now this is interesting, I thought! I could now broadcast the game state to multiple browsers, in real time! But... How could I make it &lt;em&gt;more&lt;/em&gt; interesting? I decided to give each cell a color because it looks pretty! Every player is assigned a random color when they connect. The cells also mix colors when they reproduce, creating some interesting patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization
&lt;/h2&gt;

&lt;p&gt;I found that serializing the entire game state and events in plaintext JSON was computationally very expensive and used a lot of bandwidth. I was talking to a colleague and they suggested to create a binary protocol, so I did! I also considered &lt;a href="https://developers.google.com/protocol-buffers/"&gt;Protocol Buffers&lt;/a&gt;, but I preferred to serialize the data myself.&lt;/p&gt;

&lt;p&gt;I knew the binary protocol would be especially tricky to implement, so I used a &lt;a href="https://en.wikipedia.org/wiki/Test-driven_development"&gt;Test-driven-development&lt;/a&gt; approach: I wrote initially failing &lt;code&gt;serialize&lt;/code&gt; and &lt;code&gt;deserialize&lt;/code&gt; tests for the binary protocol, each asserting that it could successfully serialize and deserialize a protocol model and then wrote the code for each method until they all passed. Unit tests are invaluable when working with complex logic.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href="https://github.com/colorjs/color-namer"&gt;color-namer&lt;/a&gt; module to name each color in the game state. However, it was inefficient at first - every time it looked up a color it iterates through the entire list of color names to compare color distance, an &lt;code&gt;O(n)&lt;/code&gt; (or linear time) operation and it did not cache the results of each color lookup. To improve the performance, I forked the repository and implemented &lt;a href="https://en.wikipedia.org/wiki/Memoization"&gt;Memoization&lt;/a&gt; by caching the results in a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap"&gt;WeakMap&lt;/a&gt;. I used a WeakMap so that the Garbage Collector would intermittently clear the cache, instead of filling up the cache forever (there are &lt;code&gt;2^24 - 1&lt;/code&gt;, or 16,777,215 possible colors that could be looked up ... ). I also implemented support for the &lt;a href="http://zschuessler.github.io/DeltaE/learn/"&gt;Delta-E&lt;/a&gt; color distance function for more accurate naming of colors. I submitted both these changes as a pull request to the module maintainer and they were eventually accepted and released.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/colorjs/color-namer/pull/9"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add Memoization, deltaE distance support
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#9&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jmercha"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--75ozGj7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars1.githubusercontent.com/u/13174322%3Fv%3D4" alt="jmercha avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jmercha"&gt;jmercha&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/colorjs/color-namer/pull/9"&gt;&lt;time&gt;Jul 13, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Greetings, I have added 2 features to this module&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added memoization / caching, resulting in a noticeable performance improvement&lt;/li&gt;
&lt;li&gt;Optionally allow for using the &lt;a href="http://zschuessler.github.io/DeltaE/learn/" rel="nofollow"&gt;Delta-E&lt;/a&gt; function for color distance&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/colorjs/color-namer/pull/9"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Deployment and Release
&lt;/h2&gt;

&lt;p&gt;It was now time to show the world what I had created! But how? Well, to host a website, I needed a server. I created a Droplet on &lt;a href="https://digitalocean.com"&gt;DigitalOcean&lt;/a&gt; to host multilife. I also purchased a domain: multilife.live. (edit: I did not renew the domain, and it has since expired and is parked by someone else now!)&lt;/p&gt;

&lt;p&gt;I set up &lt;a href="https://nginx.com"&gt;Nginx&lt;/a&gt; to host the site, and &lt;a href="http://pm2.keymetrics.io/"&gt;pm2&lt;/a&gt; to run the app, as well as &lt;a href="https://letsencrypt.com"&gt;LetsEncrypt&lt;/a&gt; to provide SSL.&lt;/p&gt;

&lt;p&gt;I also set up CI/CD using &lt;a href="https://circleci.com"&gt;CircleCI&lt;/a&gt; so that I did not have to manually deploy to production whenever I merged new code into master. CircleCI also runs my tests before deploying.&lt;/p&gt;

&lt;p&gt;After many attempts to get CI/CD working (many, many "fixing CI" commits), multilife was released and I shared it with my friends. We had a lot of fun clicking around and watching the patterns form. The site also uses responsive design, so everyone had their phones out touching on their screens!&lt;/p&gt;

&lt;h2&gt;
  
  
  MultiLife RGB
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/johnmerchant"&gt;
        johnmerchant
      &lt;/a&gt; / &lt;a href="https://github.com/johnmerchant/multilife-rgb"&gt;
        multilife-rgb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Renders multilife.live to RGB LED Matrix hardware connected to a Raspberry Pi
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
MultiLife RGB&lt;/h1&gt;
&lt;p&gt;Renders the &lt;a href="https://multilife.live" rel="nofollow"&gt;https://multilife.live&lt;/a&gt; game state to a LED RGB matrix panel connected to a Raspberry Pi&lt;/p&gt;
&lt;h2&gt;
Dependencies&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hzeller/rpi-rgb-led-matrix"&gt;rpi-rgb-led-matrix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Building&lt;/h2&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; clone repos&lt;/span&gt;
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; &lt;span class="pl-k"&gt;~&lt;/span&gt;
git clone https://github.com/jmercha/multilife-rgb
git clone https://github.com/hzeller/rpi-rgb-led-matrix

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; build librgbmatrix&lt;/span&gt;
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; &lt;span class="pl-k"&gt;~&lt;/span&gt;/rpi-rgb-led-matrix/lib
make
sudo cp librgbmatrix.so.1 /usr/lib

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; build multilife-rgb&lt;/span&gt;
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; &lt;span class="pl-k"&gt;~&lt;/span&gt;/multilife-rgb
make&lt;/pre&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/johnmerchant/multilife-rgb"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;I then wanted to take things a step further: what if I could render the game state to a RGB LED panel? Wouldn't that be cool? So I shopped around and purchased a &lt;a href="https://core-electronics.com.au/32x32-rgb-led-matrix-panel-4mm-pitch.html"&gt;32x32 RGB LED matrix panel&lt;/a&gt; and a &lt;a href="https://core-electronics.com.au/raspberry-pi-zero-w-wireless.html"&gt;Raspberry Pi Zero W&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I was wiring up the RGB LED panel, I accidentally connected a wrong pin and broke all of the electronic components in the panel - I wired 5 volts into the ground pin. Oops! I had to wait another week for a new one to arrive before I could get started. &lt;/p&gt;

&lt;p&gt;I learned a valuable lesson here: broken software is easy to fix, but you cannot easily fix broken transistors and capacitors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e5TZYCD3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/AS1TCfw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e5TZYCD3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/AS1TCfw.jpg" alt="" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote a program in C - &lt;a href="https://github.com/jmercha/multilife-rgb"&gt;multilife-rgb&lt;/a&gt; to listen to game events from the server over UDP using my binary protocol and render the cells using the &lt;a href="https://github.com/hzeller/rpi-rgb-led-matrix"&gt;rpi-rgb-led-matrix&lt;/a&gt; library. I chose UDP over TCP as it made more sense for the case I was using it for - TCP is a stream-based protocol and UDP is datagram, or message-based. I also didn't mind if messages occasionally weren't received or were in the incorrect order.&lt;/p&gt;

&lt;p&gt;I found it was very convenient to read the multilife binary protocol in C, I simply assigned a pointer to the protocol model structs to the received message buffers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although it did require using the &lt;a href="https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.html"&gt;packed attribute&lt;/a&gt; on the &lt;code&gt;Cell&lt;/code&gt; struct to align the data correctly.&lt;/p&gt;

&lt;p&gt;The end result is visually appealing, especially in the dark. I love being able to tap cells in from my phone or desktop browser and seeing it instantly appear on the matrix. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Perhaps in the future, if "mutlilife" somehow goes viral (I doubt it), I could scale it out by using &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt; and the &lt;a href="https://en.wikipedia.org/wiki/Hashlife"&gt;Hashlife&lt;/a&gt; algorithm, as well as supporting zooming and panning in the frontend and protocol.&lt;/p&gt;

&lt;p&gt;Learning by building things is fun, even if you are building something practically useless. I hope this might inspire others to learn by building the superfluous! &lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>c</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
