<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2025-12-03T09:24:32+00:00</updated><id>/feed.xml</id><title type="html">keepitwiel</title><subtitle>Copyright (c) keepitwiel. All rights reserved.</subtitle><entry><title type="html">ROMVLVS - What’s new in 2023</title><link href="/2023/11/20/another-update.html" rel="alternate" type="text/html" title="ROMVLVS - What’s new in 2023" /><published>2023-11-20T00:00:00+00:00</published><updated>2023-11-20T00:00:00+00:00</updated><id>/2023/11/20/another-update</id><content type="html" xml:base="/2023/11/20/another-update.html"><![CDATA[<p>Since the last update 8 months ago I’ve restarted the project from scratch.</p>

<p><img src="/romvlvs/images/2023-11-10-map.png" alt="Screenshot of a city" /></p>

<p>To give you a short recap, the idea behind ROMVLVS is bridge the gap between
SimCity and Civilization - build massive, detailed civilizations on huge
maps without having to micromanage (at least not too much).</p>

<p>How does it work? You simply click on the map where you want to build a city,
and buildings and roads start to appear. There is a budget, so you have to
be smart about where to build.</p>

<p>Currently at version 0.15.4, the main improvements over the last version are:</p>
<ul>
  <li>massive maps: the default is now 2000x2000 tiles</li>
  <li>user interface: I’ve finally bothered to implement an actual GUI</li>
  <li>responsiveness (60FPS at all times)</li>
  <li>hybrid grid/vector based hydrodynamics</li>
  <li>automatic road building (when adding population to map)</li>
</ul>

<p>Improvements I want to make down the line:</p>
<ul>
  <li>make rendering as realistic as possible without resorting to
a full blown 3D engine</li>
  <li>have the ability to zoom in and admire cities in detail</li>
  <li>improve the gameplay: the budget should increase based on how prosperous
the existing population is</li>
  <li>provide a macOS download</li>
</ul>

<p>Last but not least: my thanks go out to <a href="https://twitter.com/sebs_tweets">Sebastian David Lees</a> for some important alpha testing!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Since the last update 8 months ago I’ve restarted the project from scratch.]]></summary></entry><entry><title type="html">ROMVLVS2020</title><link href="/2023/03/17/ROMVLVS-update.html" rel="alternate" type="text/html" title="ROMVLVS2020" /><published>2023-03-17T00:00:00+00:00</published><updated>2023-03-17T00:00:00+00:00</updated><id>/2023/03/17/ROMVLVS-update</id><content type="html" xml:base="/2023/03/17/ROMVLVS-update.html"><![CDATA[<p>It’s been nearly 9 years since I started this blog, 
primarily about the SimCity/Civilization crossover game
I’ve been working on, and about 25 years since I first
thought about it. Time flies!</p>

<p>From <a href="https://keepitwiel.github.io/2017/07/30/ROMVLVS_engine_philosophy.html">a post</a> I wrote in 2017:</p>
<blockquote>
  <p>In short, I aim for ROMVLVS to be some sort of SimCity++, taking you from 
prehistoric to modern times while also invoking some Civ-like concepts 
such as research and warfare.</p>

  <p>ROMVLVS, like the original SimCity, leans heavily on the idea of cellular 
automata. Basically, simple rules governing the contents of tiles lead to 
very complex behaviour.</p>
</blockquote>

<p>Since the last official update in 2019, I’ve been hard
at work at reinventing the whole concept. The underlying 
philosophy is still based on cellular automata - or, more 
generally speaking, 2D differential equations - but I’ve simplified
the whole user experience. In 2020, I started with an entirely
new codebase - why not? - and renamed the project ROMVLVS2020.
(And here we are, in 2023!)</p>

<p>In the current version (v0.13.9.2), the building 
selection menu is gone. The reason: if you want to simulate a 
gigantic map where a single tile represents 10x10 meters, you’re 
not going to enjoy micromanaging every addition to your city.</p>

<p>Instead, you dump a cloud of people on the map and let the engine
build the city. Here is a short video showing a city being built:</p>

<p><img src="/romvlvs/images/2023-03-17-building-city.gif" alt="Building a city" /></p>

<h2 id="a-brief-history-of-romvlvs2020">A brief history of ROMVLVS2020</h2>

<p>In the new codebase, I originally wanted to have city centers 
represented by distinct objects, so the engine could 
automatically create roads between cities. Also, it would 
help keeping track of city population and the likes. In turn,
city population would determine the city limits.</p>

<p>Here you can see the new concept in an early screenshot (version unknown):</p>

<p><img src="/romvlvs/images/2023-03-17-city-centers.png" alt="City centers, roads" /></p>

<p>Below is an iteration which includes forests and rivers.
The roads evolved over time: the closer two cities were
together, the bigger the roads were. As a bonus, 
it has a nice pixely feel to it (v0.7.7):</p>

<p><img src="/romvlvs/images/2023-03-17-city-centers-2.png" alt="City centers, roads, rivers" /></p>

<p>However, keeping city objects and the map grid as separate 
entities somehow didn’t work great. For each city, a separate
map needed to be kept to indicate the city limits. And what
would happen where two cities meet - which city owns which tile?</p>

<p>On top if that, I started noticing performance issues. The more cities,
the more pathfinding you have to do to connect them by roads.</p>

<h2 id="no-more-city-centers">No more city centers</h2>
<p>Instead, I started to populate the map directly - in a later
stage I would have to add a postprocessing layer indicating
which blob of people would become a village, town or city.</p>

<p>Immediately you can see the benefit - a 1280x800 map operating at 60fps (v0.9.0):</p>

<p><img src="/romvlvs/images/2023-03-17-direct-population.png" alt="Direct population" /></p>

<p>Notice also the river network - this started to bother me, and needed to fix it.</p>

<h2 id="rivers">Rivers</h2>

<p>The way I calculated rivers was as follows:</p>
<ul>
  <li>I randomly selected a point on the map.</li>
  <li>I let a “raindrop” fall from that point to the 
coastline.</li>
  <li>The resulting path was the river.</li>
</ul>

<p>This is a nice beginning, but there are some problems:</p>
<ul>
  <li>Rivers sometimes stop inland and never create lakes; therefore
there can never be “buffer lakes” that first fill up
after which the river proceeds on its journey to the ocean.</li>
  <li>Rivers always are 1 tile wide.</li>
  <li>“compounding” rivers creates a nice tributary effect, where 
streams from different origins converge to a big river, but
they never grow wider or cause the river flow to behave
differently (a small stream will flow through the land different
from a big one).</li>
  <li>Rivers don’t influence the global water level.</li>
  <li>Rivers are separate entities from the ocean, creating overhead.</li>
  <li>There is no erosion.</li>
</ul>

<p>I needed to introduce some kind of hydrodynamical model to solve this.</p>

<h2 id="hydrodynamics">Hydrodynamics</h2>

<p>Long story short, I adapted a freely available model that worked well
enough for my needs. You can find my version <a href="https://github.com/keepitwiel/hydraulic-erosion-simulator">here</a>.</p>

<p>The benefits of using this model are:</p>

<ul>
  <li>It integrates very easily into the existing engine.</li>
  <li>It unifies the existing “ocean” and “river” layers into one “water” layer.</li>
  <li>I don’t need to use pathfinding to determine river paths.</li>
  <li>It allows lakes with in- and outflow.</li>
  <li>Rivers can have varying depth and width.</li>
  <li>It allows water velocity, sediment and erosion.</li>
</ul>

<p>Here you can see the result (v0.13.0) - looks pretty cool:</p>

<p><img src="/romvlvs/images/2023-03-17-hydrodynamics.png" alt="Hydrodynamics" /></p>

<p>Performance is an issue right now, but because the 
hydrodynamical model doesn’t need to run in real time, 
we can dial down on the computations.</p>

<h2 id="population-revisited">Population, revisited</h2>

<p>After implementing the hydrodynamics, I could get back to 
the actual city/civilization aspect, which had been relegated 
to the background a bit.</p>

<p>The eternal question is: where does the user input end,
and where does the engine take over? As I mentioned earlier,
micromanagement was out - building individual roads and
buildings seemed like too much of a chore.</p>

<p>As a starting point, I settled on a pure simulation:
seeding the map with some initial population, and let the
engine figure out population growth, roads, second order
interactions and so on. I would figure out the user part
later.</p>

<p>Automatic road building is a relatively easy concept - 
find a start and end point, and let a pathfinding algorithm
determine where the road goes. Like with rivers, 
compounding roads creates a nice differentiating effect.
As you can imagine, if you let population density determine
start and end point, your big roads will end up going
between big cities, while the smaller ones are between towns,
etc.</p>

<p>To take this even further, you can use this approach to 
build a very realistic “medieval” city grid as shown here (v0.13.7.5):</p>

<p><img src="/romvlvs/images/2023-03-17-city-roads.png" alt="Medieval city grid" /></p>

<p>Brighter colors mean a more densely used road.</p>

<p>Again, there is a drawback: by this point I’d let 
population influence where roads were built, and in 
turn roads determined where population 
would go. This feedback loop meant that the highest
population density was on the roads themselves,
not in the areas between them!</p>

<p>Therefore, I’m leaving roads out at the moment. I
did briefly think of using the hydrodynamic model to
simulate roads, but that requires some brainpower
to figure out all the analogies. Here’s a “city” as
it is right now, without roads:</p>

<p><img src="/romvlvs/images/2023-03-17-no-roads.png" alt="No more roads" /></p>

<p>As for population growth, there is currently none.
A user can now just add population by pointing and
clicking on the map, like a paintbrush.</p>

<h2 id="lighting">Lighting</h2>

<p>As you can tell, over time I’ve changed the colors 
and lighting a lot. Right now, I’m using a very simplified
raytracing approach, where each tile (equivalent to 1 pixel)
shoots a ray to the sun. If it is blocked, only ambient
reflection is shown.</p>

<p>The problem (as you can imagine) comes when we want to determine
 lighting on a water tile. Again, this is something for later.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I’m very proud of what I’ve achieved so far. But challenges 
remain.</p>

<p>First and foremost, the boundary between user input and game engine.
Am I going to make an entirely passive simulator, or should I
bring in some interaction? And where does that end?</p>

<p>Next, population growth - it’s difficult to set parameters where
population grows steadily into a nice city, and then reaches some
kind of limit. From experience, either it shrinks to nothing or
grows out of control.</p>

<p>Also, what determines population growth - food? Where does it 
come from? And is it in turn influenced by population? I 
experimented with a concave food production “curve” that 
was highest at some population level, and then gradually sloped
down. As you can imagine, it’s hard to grow food in a city
center, but easier on the outskirts.</p>

<p>So for now, I’m going to stick with the population 
“paintbrush” mode. I think for now the value is in reinventing
the road generation algorithm, increasing FPS and working out
the graphics layer - have some kind of simple rules that
generate a vibrant, complex looking city.</p>

<p>Thanks for reading and until the next post!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[It’s been nearly 9 years since I started this blog, primarily about the SimCity/Civilization crossover game I’ve been working on, and about 25 years since I first thought about it. Time flies!]]></summary></entry><entry><title type="html">Fun with generative music, part one</title><link href="/2022/06/12/automatone.html" rel="alternate" type="text/html" title="Fun with generative music, part one" /><published>2022-06-12T00:00:00+00:00</published><updated>2022-06-12T00:00:00+00:00</updated><id>/2022/06/12/automatone</id><content type="html" xml:base="/2022/06/12/automatone.html"><![CDATA[<p><img src="../../../automatones/images/wolfram_rule30.png" alt="Rule 30, 256x32 cells, random initial setting" /></p>

<h2 id="introduction">Introduction</h2>
<p>As a lazy person, I want to achieve the most by doing the least. As a lazy <em>musician</em>, I want to create music out of thin air at the push of a button. But how? I’ve been thinking about this problem for a while and in this post I will show you my initial approach in solving it.</p>

<h3 id="the-creative-process">The Creative Process</h3>
<p>Creating music is a rewarding but also time consuming process. From personal experience, the problem is mostly one of creative control. It usually boils down to this: everything you can tweak must be tweaked.</p>

<p>From melody to frequency balancing to reverb levels to stereo panning - you always have the feeling that something can be better and the last 1% of perfection takes 99% of effort. This is why it sometimes takes me 10 years to finish a track: it’s good but never good enough.</p>

<h2 id="the-art-of-letting-go">The Art Of Letting Go</h2>
<p><img src="../../../automatones/images/wolfram_rule106.png" alt="Rule 106, 256x32 cells, random initial setting" /></p>

<p>So, in order to speed up the process, why not accept that some things cannot be controlled? And if you take that to its limit, why not let some other process (say, algorithms) do the dirty work?</p>

<h3 id="generative-music">Generative Music</h3>
<p>Algorithmically generated music or generative music is as old as <a href="https://quod.lib.umich.edu/s/spobooks/bbv9810.0001.001/1:5/--algorithmic-composition-a-gentle-introduction-to-music?rgn=div1;view=fulltext">Medieval 
times</a> 
and is a well established art form, with Steve Reich and Brian Eno as well-known artists. A very nice introduction to generative music can be found <a href="https://teropa.info/loop/">here</a>.</p>

<p>In my personal interpretation, generative music creates sounds that are perceptionally more complex than the seemingly simple rules that generate them.</p>

<p>Still thinking with my lazy cap on, which rules are the simplest yet create an abundance of complexity?</p>

<h3 id="wolfram-and-cellular-automata">Wolfram and Cellular Automata</h3>

<p>The graphics you have seen so far on this page have an interesting trait: the patterns seem to be repetitive yet with a degree of unpredictableness in it. They are technically not random - the images are generated using deterministic rules - but there is no simple explanation for this emergent behavior.</p>

<p>The rules used are elementary cellular automata and were popularized by Stephen Wolfram in his seminal book <a href="https://www.wolframscience.com/">A New Kind of Science</a>. What they do is the following:</p>

<ul>
  <li>start with a row of 0s and 1s. These can be chosen arbitrarily;</li>
  <li>apply one of 256 <a href="https://en.wikipedia.org/wiki/Elementary_cellular_automaton">elementary rules</a> to this row;</li>
  <li>you obtain a new row with different 0s and 1s.</li>
</ul>

<p>Here’s an example of how Rule 30 is applied. In our case we start with a row containing only zeros, except for the middle element:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Initial row:   0, 0, 0, 0, 1, 0, 0, 0, 0 
Iteration 1:   0, 0, 0, 1, 1, 1, 0, 0, 0
Iteration 2:   0, 0, 1, 1, 0, 0, 1, 0, 0 
Iteration 3:   0, 1, 1, 0, 1, 1, 1, 1, 0
</code></pre></div></div>

<p>As you see, we get a sequence of rows that are not quite repetitive yet also not entirely random. You could say that’s something we want out of music - a limited sequence of sounds that are somewhat repetitive yet not boring.</p>

<p>Music generated by cellular automata is already a thing: on Wolfram’s website there’s this <a href="http://tones.wolfram.com">incredible generator</a> that I encourage you to play with.</p>

<p>Now, with me being stubborn and wanting to do things my own way, I decided to create a program from scratch that does roughly the same thing. For lack of imagination I decided to call it: <a href="https://github.com/keepitwiel/just-another-music-generator">Automatone</a>.</p>

<h2 id="automatones">Automatones</h2>
<p><img src="../../../automatones/images/wolfram_rule110.png" alt="Rule 110, 256x32 cells, random initial setting" /></p>

<p>So, what is an Automatone? It is a matrix of zeros and ones, generated by cellular automata, where a one triggers a sound and a zero does nothing. For example, in the following matrix, three different sounds are triggered at different time intervals:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0, 0, 0, 0, 1, 0
0, 1, 0, 0, 0, 0
0, 0, 0, 1, 0, 0
</code></pre></div></div>

<p>If you imagine time going from left to right, and each row representing a different note or instrument, you can kind of imagine what it would sound like. In essence this is just another form of sheet music.</p>

<p>For the time being, I’m using a simple sine oscillator as an instrument, and let each row represent a different frequency of that instrument. To recap: each “one” in the matrix triggers a short sine tone with a specific frequency.</p>

<p>So what does this actually sound like?</p>

<h3 id="experiments">Experiments</h3>
<p>Going back a bit, I said I wanted to magically create music at the press of a button. The software I wrote can do that - follow the instructions on the <a href="https://github.com/keepitwiel/just-another-music-generator">main page</a> if you want to experiment yourself!</p>

<p>Here’s a graph of a simple Automatone that applies Rule 30 to a range of 257 frequencies (vertical axis) for 256 time steps (horizontal axis):</p>

<p><img src="../../../automatones/images/experiment0.png" alt="Automatone Experiment 0" /></p>

<p>You can see that the frequency range is quite large - so large even that apart from the top 30 or so frequencies, the resulting output would be inaudible. Moreover, because I’ve set the rendering sample rate to 96kHz, there are a lot of artifacts. In other words, most inaudible frequencies are going to be rendered at a completely different (audible) frequency.</p>

<p>Not to worry though, because it sounds kinda cool - and to be honest, creepy!</p>

<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1285544965&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true"></iframe>
<div style="font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;"><a href="https://soundcloud.com/the-starkiller" title="The Starkiller" target="_blank" style="color: #cccccc; text-decoration: none;">The Starkiller</a> · <a href="https://soundcloud.com/the-starkiller/automatone-v071-experiment-0" title="Automatone v0.7.1 experiment 0" target="_blank" style="color: #cccccc; text-decoration: none;">Automatone v0.7.1 experiment 0</a></div>

<p>Because there are a lot of tones being triggered together, it still sounds very random and unstructured. So, I included a parameter <code class="language-plaintext highlighter-rouge">n_rules</code>. This value indicates how many rules we are applying - if it is 2, then we take two cellular automaton rules and elementwise multiply the results with each other.</p>

<p>Here is another experiment where 5 rules are applied instead of one (we unfortunately don’t get to choose which rules, it’s something I still need to fix). I also limited the tone range to 24. You can see the trigger density is much lower:</p>

<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1284795997&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true"></iframe>
<div style="font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;"><a href="https://soundcloud.com/the-starkiller" title="The Starkiller" target="_blank" style="color: #cccccc; text-decoration: none;">The Starkiller</a> · <a href="https://soundcloud.com/the-starkiller/automatone-v071-example-1" title="Automatone v0.7.1 example 1" target="_blank" style="color: #cccccc; text-decoration: none;">Automatone v0.7.1 example 1</a></div>
<p><br /></p>

<p>And here, some more experiments. You can find the configuration parameters in the description of each link. What struck me is that there is still quite some repetition going on, possibly because of a bad implementation of the cellular automata:</p>

<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1284797185&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true"></iframe>
<div style="font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;"><a href="https://soundcloud.com/the-starkiller" title="The Starkiller" target="_blank" style="color: #cccccc; text-decoration: none;">The Starkiller</a> · <a href="https://soundcloud.com/the-starkiller/automatone-v071-example-2" title="Automatone v0.7.1 example 2" target="_blank" style="color: #cccccc; text-decoration: none;">Automatone v0.7.1 example 2</a></div>
<p><br /></p>

<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1284798667&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true"></iframe>
<div style="font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;"><a href="https://soundcloud.com/the-starkiller" title="The Starkiller" target="_blank" style="color: #cccccc; text-decoration: none;">The Starkiller</a> · <a href="https://soundcloud.com/the-starkiller/automatone-v071-example-3" title="Automatone v0.7.1 example 3" target="_blank" style="color: #cccccc; text-decoration: none;">Automatone v0.7.1 example 3</a></div>
<p><br /></p>

<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1284799669&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true"></iframe>
<div style="font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;"><a href="https://soundcloud.com/the-starkiller" title="The Starkiller" target="_blank" style="color: #cccccc; text-decoration: none;">The Starkiller</a> · <a href="https://soundcloud.com/the-starkiller/automatone-v071-example-4" title="Automatone v0.7.1 example 4" target="_blank" style="color: #cccccc; text-decoration: none;">Automatone v0.7.1 example 4</a></div>
<p><br /></p>

<h2 id="future-work">Future work</h2>
<p><img src="../../../automatones/images/wolfram_rule90.png" alt="Rule 90, 256x32 cells, random initial setting" /></p>

<p>I have many more ideas on how to proceed. The first is to use different combinations of rules for the left and right stereo tracks. The second is to combine all rules found in the left and right track to create a center track, which will - by definition - contain less triggers. In the next blog post I will try to elaborate on this. Thirdly, instead of multiplying each rule matrix I could also add them up and use the resulting value as a volume indicator.</p>

<p>Next I want to go deeper and use automata to create a <em>change</em> in the frequency spectrum rather than define it.</p>

<p>Ultimately, automata can be applied to any arbitrary instrument or effect setting: tweaking reverbs, phasers, delays, you name it. Even visuals can be manipulated like this.</p>

<p>Looking back, I made a thing that can automatically create “music” - however the sweat is now in creating the software rather than the music itself…</p>

<p>Thank you for your attention,</p>

<p><em>keepitwiel</em></p>]]></content><author><name></name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">More fun with Recurrent Neural Networks - The Big Lebowski</title><link href="/2022/05/23/rnn-lebowski.html" rel="alternate" type="text/html" title="More fun with Recurrent Neural Networks - The Big Lebowski" /><published>2022-05-23T00:00:00+00:00</published><updated>2022-05-23T00:00:00+00:00</updated><id>/2022/05/23/rnn-lebowski</id><content type="html" xml:base="/2022/05/23/rnn-lebowski.html"><![CDATA[<p>My view of machine learning (from a software development perspective) is: letting software create other software by providing training material, as opposed to letting humans create software.</p>

<p>Within machine learning (ML), I understand Convolutional Neural Networks (CNNs), but have been struggling a bit with Recurrent Neural Networks (RNNs). So I set out to explore and learn!</p>

<h2 id="background">Background</h2>

<p>The following description by <a href="https://twitter.com/karpathy">Andrej Karpathy</a> in his <a href="http://karpathy.github.io/2015/05/21/rnn-effectiveness/">seminal blog post</a> stuck with me:</p>

<blockquote>
  <p>If training vanilla neural nets is optimization over functions, training recurrent nets is optimization over programs.</p>
</blockquote>

<p>Combining this statement with my view on ML above, you can say the following:</p>

<ul>
  <li>
    <p>with CNNs, the created software is a “stateless” function, where you feed it a single input of fixed size;</p>
  </li>
  <li>
    <p>With RNNs you actually create a program with variables that depend on an initial state; that state changes over time by continuously feeding the RNN new inputs.</p>
  </li>
</ul>

<p>Karpathy gives an example how to train an RNN on the entirety of Shakespeare’s works - with the goal of generating “new” Shakespeare material. From that blog post, here’s an example of freshly generated “AI Shakespeare”:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PANDARUS:
Alas, I think he shall be come approached and the day
When little srain would be attain'd into being never fed,
And who is but a chain and subjects of his death,
I should not sleep.
</code></pre></div></div>

<p>Amazing, right? It’s gibberish, but it sure sounds like Shakespeare! I wanted to do the same.</p>

<h2 id="make-your-own-rnn">Make your own RNN</h2>
<p>Tensorflow has a <a href="https://www.tensorflow.org/text/tutorials/text_generation">tutorial</a> that lets you reproduce Karpathy’s work. The good boyscout in me faithfully copied and pasted the provided code into a Jupyter Notebook and let it run. Using the same Shakespeare training set, I generated the following wonderful prose:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ROMEO:
I do pretent to Rome, come; Momed that,
For mirroant-tongued together, to thy lord,
Upon so orperalling me speak to him:
Some hath mother, throw up ta live, that thousand faithant
Well-counio so, without decay: descend at dayman
Citizens doth cry it so well;
No man belseit in fore and Die Richmond!
</code></pre></div></div>

<h2 id="enter-the-dude">Enter The Dude</h2>

<p>(Side note: if you haven’t read <a href="https://www.amazon.com/Two-Gentlemen-Lebowski-Excellent-Tragical/dp/1451605811">Two Gentlemen of Lebowski</a>, you should. It’s The Big Lebowski written as a Shakespeare play.)</p>

<p>I love The Big Lebowski, the Coen brothers’ 1998 cult film, so what could be better than generating more Lebowski using RNNs?</p>

<p>I took the exact same notebook as above and replaced the source text with the Big Lebowski screenplay. Here’s a few lines from the input:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The Dude, also holding a large plastic cup of Bud, wears
some of its foam on his mustache.

                WALTER
        This was a valued rug.

He elaborately clears his throat.

                WALTER
        This was, uh--

                DUDE
        Yeah man, it really tied the room
        together--

                WALTER
        This was a valued, uh.
</code></pre></div></div>

<h2 id="training-the-rnn">Training the RNN</h2>

<p>(I will not go into detail on how the training process works or how to generate output - you should really check out the tutorial!)</p>

<p>By training, we teach the RNN to correctly “predict” characters given a set of preceding input text of fixed length. So if the input text is <code class="language-plaintext highlighter-rouge">The Dude, also holding a large plastic cup of Bu</code> then the correct prediction would be the character <code class="language-plaintext highlighter-rouge">d</code>. If we do this with a large enough set of samples, and train often enough, the RNN should become accurate enough to predict meaningful texts.</p>

<p>Generating new text is really simple:</p>

<ul>
  <li>
    <p>you provide the RNN with a prompt - for example, <code class="language-plaintext highlighter-rouge">JACKIE TREEHORN</code>;</p>
  </li>
  <li>
    <p>it will predict the next character;</p>
  </li>
  <li>
    <p>you append that character to the prompt;</p>
  </li>
  <li>
    <p>repeat.</p>
  </li>
</ul>

<h3 id="after-10-training-rounds">After 10 training rounds</h3>

<p>Here’s what the RNN comes up with after 10 rounds (“epochs”) of training:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                MABWYOR

Thy in's bonel
        decoutery gam.

                AADTER
        HER LEIBMALSSY?
        Fucke.  Wantee hishe gowt on Beyo
        ar on the I'
        youre, ma.  I dowallyote, Luy full, wo siatlo, Wat mar, uhingeyes.
</code></pre></div></div>

<p>First off - the model doesn’t fully understand the standard screenplay formatting rules. (Or as Walter would say: This isn’t ‘Nam.)</p>

<p>Secondly - the characters sound like they either had their tongue paralyzed or are regulars in a Scottish pub - or both.</p>

<p>Clearly, the RNN doesn’t “know” the source text well enough to make intelligible predictions.</p>

<p>Here’s some more:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                DUDE
        I told money you one moneys to
everything.  On a fucting exering them's the emblams.  He is the Wobar.  All fitter, and
        they poinet of as he spiph you un, Dude.

                DUDE
        I'm gettink on the rail, rest you're-

                DUDE
        .... uh, but--

                MAUDE
        --word it for you.  That's your vairbox?
</code></pre></div></div>

<h3 id="after-20-more-rounds">After 20 more rounds</h3>

<p>It’s getting a bit more readable now - although it all still sounds very “drunk”:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Walter blung some zarmout and will.

                DUDE
        You're gain got about the fucking
        occusior luce?

Walter prudes in to plase, he wnops with flishor is taked open the Dude's car.,
Dieter, it the phone him of geeting in slow motion.  Me and headle askig the Dude turns thrown
outing from the satchel put of his head.
out for it, his irmothing into the three men turn to loen.

                DUDE
        This fucking eaty mininess.
</code></pre></div></div>

<p>I’m snorting milk out of my nose right now:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DUDE
        What the fuck are you talking about?

                LEBOWSKI
        Well, All you something, is suckeds, I dan from
        which leng git home of Lebowski?

                WALTER
        Huh?  Oh, this fuck is the busi?

        Soothim. I'm not if--

                LEBOWSKI
        You got a whole cates--

                DUDE
        Who the fuck're you talking about?

                DUDE
        Now that fom he mistly handle
        ago?  Dude is Walter Solfbacks!  AM
        SCOKHY BOWLING IS IN WAL, Ar A lar, Alleady!
</code></pre></div></div>

<h3 id="20-more-rounds">20 more rounds</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Walter bashes him a few more time on ole almonatapal, then quiet.  Laid out now, Franz too is
Bunny Lebowski, falfing at etwing.

                DUDE
        What's your point, Walter?

                WALTER
        You're just looking for a handout
        look, a dos in one hands in take
        forlet my dight.

                DUDE
        No.  Here.

                YOUNGER COP
        Separate incidents?

The Dude steps out to meet Walter's car as it ruds blowing ball.
</code></pre></div></div>

<p>By this point, I think it shows that the Big Lebowski script is a mere 131 thousand characters long. There’s only so much you can train your RNN on before you start recreating it line by line.</p>

<h2 id="whats-next">What’s next</h2>

<p>To overcome the limited input, I’ve been thinking about combining many different movie scripts set in Los Angeles - Chinatown, The Big Lebowski, Blade Runner, To Live and Die in L.A., Point Break, Falling Down, Die Hard, L.A. Confidential (to name a few) and do the same thing. I predict lots of ins, outs, what-have-yous all set in a dreamscape meta retro-futuristic Los Angeles…</p>

<p>Also, to make the text more meaningful, the RNN should have some notion of “attention” - there needs to be some kind of character and environment persistence.</p>

<p>On that note:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                VOICE-OVER
        sometimes there's a man. . . sometimes
        there's a man.
        
        Wal, I lost m'train of thought here.
        But--aw hell, I done innerduced him
        enough.
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[My view of machine learning (from a software development perspective) is: letting software create other software by providing training material, as opposed to letting humans create software.]]></summary></entry><entry><title type="html">Development Update</title><link href="/2019/08/27/development_update.html" rel="alternate" type="text/html" title="Development Update" /><published>2019-08-27T00:00:00+00:00</published><updated>2019-08-27T00:00:00+00:00</updated><id>/2019/08/27/development_update</id><content type="html" xml:base="/2019/08/27/development_update.html"><![CDATA[<p>After last week’s alpha demo release, I’ve started 
implementing some new features:</p>

<ul>
  <li>
    <p>Cursor: you can now see what you’re building, and 
whether it’s possible to build, using the cursor.</p>
  </li>
  <li>
    <p>Message panel: any important messages will appear 
in the message panel at the bottom of the screen. 
For now, it’s mostly warnings and welcome messages.</p>
  </li>
</ul>

<p>Here’s a video of the latest development build containing these features:</p>

<iframe width="600" height="400" src="https://www.youtube.com/embed/cNHQ4PmrOGA" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; 
picture-in-picture" allowfullscreen=""></iframe>]]></content><author><name></name></author><summary type="html"><![CDATA[After last week’s alpha demo release, I’ve started implementing some new features:]]></summary></entry><entry><title type="html">ROMVLVS v0.1 alpha release</title><link href="/2019/08/20/ROMVLVS-v0.1-alpha-release.html" rel="alternate" type="text/html" title="ROMVLVS v0.1 alpha release" /><published>2019-08-20T00:00:00+00:00</published><updated>2019-08-20T00:00:00+00:00</updated><id>/2019/08/20/ROMVLVS-v0.1-alpha-release</id><content type="html" xml:base="/2019/08/20/ROMVLVS-v0.1-alpha-release.html"><![CDATA[<p>If you like free downloads and use macOS, check out the latest ROMVLVS 
release in the <a href="/downloads.html">downloads</a> section!</p>

<p>I promise there will be releases for Windows and Linux as well 
in the future :)</p>]]></content><author><name></name></author><summary type="html"><![CDATA[If you like free downloads and use macOS, check out the latest ROMVLVS release in the downloads section!]]></summary></entry><entry><title type="html">A new alpha release coming soon</title><link href="/2019/07/17/a-new-start.html" rel="alternate" type="text/html" title="A new alpha release coming soon" /><published>2019-07-17T00:00:00+00:00</published><updated>2019-07-17T00:00:00+00:00</updated><id>/2019/07/17/a-new-start</id><content type="html" xml:base="/2019/07/17/a-new-start.html"><![CDATA[<p>As usual, it’s been a while since I worked on ROMVLVS.</p>

<p>My handle is now <code class="language-plaintext highlighter-rouge">keepitwiel</code> as opposed to <code class="language-plaintext highlighter-rouge">CaptainHennessey</code>. I am now 
the proud founder of Keepitwiel Studios!</p>

<p>I’ve moved the blog/website to Github Pages, but the older blog 
still lives at <a href="https://romvlvsgame.tumblr.com">Tumblr</a>. I might
move that content here at some point.</p>

<p>I’m putting the finishing touches on a new alpha release (v0.1) that can be
freely downloaded.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[As usual, it’s been a while since I worked on ROMVLVS.]]></summary></entry><entry><title type="html">A 400x400 map in ROMVLVS</title><link href="/2017/08/01/a_400x400_map.html" rel="alternate" type="text/html" title="A 400x400 map in ROMVLVS" /><published>2017-08-01T00:00:00+00:00</published><updated>2017-08-01T00:00:00+00:00</updated><id>/2017/08/01/a_400x400_map</id><content type="html" xml:base="/2017/08/01/a_400x400_map.html"><![CDATA[<blockquote class="imgur-embed-pub" lang="en" data-id="a/6pGIH">
<a href="//imgur.com/a/6pGIH">A 400x400 map in ROMVLVS</a></blockquote>
<script async="" src="//s.imgur.com/min/embed.js" charset="utf-8"></script>

<p>Yeah the GIF takes a while to load, but at least you get a sense of 
what the engine is capabe of at the moment. I use Numpy to handle 
all the low level storing of data which is pretty fast - even at 
this size, I haven’t had any scaling issues so far.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A 400x400 map in ROMVLVS]]></summary></entry><entry><title type="html">ROMVLVS engine philosophy</title><link href="/2017/07/30/ROMVLVS_engine_philosophy.html" rel="alternate" type="text/html" title="ROMVLVS engine philosophy" /><published>2017-07-30T00:00:00+00:00</published><updated>2017-07-30T00:00:00+00:00</updated><id>/2017/07/30/ROMVLVS_engine_philosophy</id><content type="html" xml:base="/2017/07/30/ROMVLVS_engine_philosophy.html"><![CDATA[<p>In short, I aim for ROMVLVS to be some sort of SimCity++, taking you from 
prehistoric to modern times while also invoking some Civ-like concepts 
such as research and warfare.</p>

<p>ROMVLVS, like the original SimCity, leans heavily on the idea of cellular 
automata. Basically, simple rules governing the contents of tiles lead to 
very complex behaviour.</p>

<p>The original concept popularized by Conway is very binary (either life 
exists on a tile or not); SimCity made use of difference equations in 
order to increase or decrease the quantity of e.g. population on a tile. 
This is the same in ROMVLVS. A simplified set of equations might look like 
this (<code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> are quantities to be increased/decreased, <code class="language-plaintext highlighter-rouge">t</code> is time, <code class="language-plaintext highlighter-rouge">t+1</code>
 is the time at the next turn):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x(t+1) = x(t) + C1 * x(t) + C2 * y(t)
y(t+1) = y(t) + C3 * x(t) + C4 * y(t)
</code></pre></div></div>

<p>In SimCity you were free to build wherever you wanted, as long as you had 
enough money to do so. The existing infrastructure generates taxes, which 
fills the city coffers.</p>

<p>In ROMVLVS, there is no money. Or, at least, not centralized. If you don’t 
have resources available in a specific tile to build something, you can’t 
build it, even though it’s available on other tiles.</p>

<p>So how do resources spread around? This is where dispersion comes in place. 
Think of an inflatable pool in your back yard. When you pierce it, it will 
empty out in rapid pace, flooding its surroundings. The more time goes by, 
the more dispersed the water is, eventually flooding your entire garden 
with a thin layer of water.</p>

<p>In ROMVLVS, dispersion works as follows: if you have a farm producing 1 
unit of food per turn, a small percentage of that (say 10%) gets dispersed 
to the four surrounding tiles. Your farm will be left with 0.9 units while 
its neighbors get 0.025 units each. Those neighboring tiles will disperse 
10% of 0.025 to their neighbors in the next turn.</p>

<p>In order to keep infinitisemally small amounts of resources spreading 
around the map, there’s a dispersion threshold.</p>

<p>At the beginning of a game, you start with a Settlement and 5 people (all 
living in the Settlement). The Settlement produces Culture (quite an 
abstract resource) which starts spreading outward over time. The difference 
equation governing the growth of people is such that Culture is a positive 
factor - i.e.:</p>

<p><code class="language-plaintext highlighter-rouge">Humans = Humans + CULTURE_FACTOR * Culture</code></p>

<p>Now, resources like Food have also a similar positive influence whereas 
proximity to enemies, extreme temperatures etc. will negatively impact 
human growth.</p>

<p>This basically describes the ROMVLVS engine. The trick is to balance out 
all the different resources: adjusting growth and dispersement parameters, 
adding buildings that modify growth even further, and adding resources that 
counterbalance other resources. So far, only Culture, Humans, Food and Wood 
are “active” resources that can be altered; I’ve thought about adding things 
like Disease, Fear, Stone, Bronze, Meat, Fruit, etc. etc.</p>

<p>Hope you enjoyed this behind-the-scenes look!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[In short, I aim for ROMVLVS to be some sort of SimCity++, taking you from prehistoric to modern times while also invoking some Civ-like concepts such as research and warfare.]]></summary></entry><entry><title type="html">ROMVLVS - building only farms</title><link href="/2017/07/29/building_only_farms.html" rel="alternate" type="text/html" title="ROMVLVS - building only farms" /><published>2017-07-29T00:00:00+00:00</published><updated>2017-07-29T00:00:00+00:00</updated><id>/2017/07/29/building_only_farms</id><content type="html" xml:base="/2017/07/29/building_only_farms.html"><![CDATA[<blockquote class="imgur-embed-pub" lang="en" data-id="a/LudrQ">
<a href="//imgur.com/a/LudrQ">ROMVLVS - building only farms</a>
</blockquote>
<script async="" src="//s.imgur.com/min/embed.js" charset="utf-8"></script>

<p>New in ROMVLVS: farms. The food they produce increases the 
population significantly. Here’s a GIF to show you how it works!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[ROMVLVS - building only farms]]></summary></entry></feed>