<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>journal.stuffwithstuff.com</title>
  <link href="http://journal.stuffwithstuff.com/"/>
  <link type="application/atom+xml" rel="self" href="http://journal.stuffwithstuff.com/atom.xml"/>
  <updated>2018-05-19T08:30:05-07:00</updated>
  <id>http://journal.stuffwithstuff.com/</id>
  <author>
    <name>Robert Nystrom</name>
    <email>robert@stuffwithstuff.com</email>
  </author>

  
  <entry>
    <id>http://journal.stuffwithstuff.com/2018/05/19/40-songs</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2018/05/19/40-songs"/>
    <title>40 Songs</title>
    <published>2018-05-19T00:00:00-07:00</published>
    <updated>2018-05-19T00:00:00-07:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;p&gt;I turned 40 today. Well, actually, as I&amp;rsquo;m writing this, I&amp;rsquo;m not yet 40. And,
unless you happen to be reading this on the very day I post it, it&amp;rsquo;s no longer
my birthday. Chronology in text is weird.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not gonna lie. This number is hitting me hard. Intellectually, I get that
the fact that it&amp;rsquo;s a round number is merely an artifact of our base ten numeral
system, which is in turn an arbitrary quirk of the evolutionary history that led
to us having ten fingers. I get it.&lt;/p&gt;

&lt;p&gt;But what it really feels like is the midpoint. As a male in the US, 40 isn&amp;rsquo;t
that far from the halfway point of average life expectancy. I have more memories
accrued than new experiences to anticipate. In the great hallway of life, there
are more doors behind me than ahead, which makes the regret of those unopened
ones all the more acute.&lt;/p&gt;

&lt;p&gt;I was talking about all this with my sister-in-law a few months ago. Her
milestone is coming soon too. She plans to celebrate by writing a list of her
top forty favorite songs. I&amp;rsquo;ll be damned if I don&amp;rsquo;t love a good list, so here&amp;rsquo;s
mine.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s in chronological order &lt;em&gt;of my personal relationship to the song&lt;/em&gt;. It
appears when it appeared in my life. The luxury of this being my list is that I
get to scramble time as it suits me.&lt;/p&gt;

&lt;p&gt;40 is a pretty long list of songs. Heck, some days it feels like a long list of
years. So we&amp;rsquo;re going to need some speed, and what better way to get moving
then&amp;hellip;&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Vppbdf-qtGU&quot;&gt;La Grange&lt;/a&gt;&lt;/strong&gt; - ZZ Top&lt;/h3&gt;

&lt;p&gt;As you&amp;rsquo;ll find out, I live for a good build-up, and there is none better than
this. A couple of sticks on the edge of the snare and a palm-muted riff and
&lt;em&gt;holy crap what just happened to my pulse&lt;/em&gt;. ZZ Top is possibly the &lt;em&gt;tightest&lt;/em&gt;
band that ever lived. Every punchy ghost hit on the snare is so locked into the
guitar and bass that it must have been played by a single giant six-armed demon.&lt;/p&gt;

&lt;p&gt;If your car is on fumes, wheezing out its last few yards, threatening to leave
you stranded in the desert, crank this song up and I promise you you&amp;rsquo;ll get
another mile or two out of the tank.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=qeMFqkcPYcg&quot;&gt;Sweet Dreams (Are Made of This)&lt;/a&gt;&lt;/strong&gt; - Eurythmics&lt;/h3&gt;

&lt;p&gt;This is the first song that I distinctly remember hearing for the first time.
Picture tiny me standing in front of a TV, staring mouth agape at Annie Lennox&amp;rsquo;s
bright red hair and that weird-ass video, wondering what the hell was going on
and why I liked it so much.&lt;/p&gt;

&lt;p&gt;I sometimes wonder if imprinting on this song at such a young age twisted my
brain. Lord knows I love a synth bassline and a four on the floor kick to an
unhealthy degree. That thing I have for short hair on women must have come from
somewhere.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=yRYFKcMa_Ek&quot;&gt;Maneater&lt;/a&gt;&lt;/strong&gt; - Daryl Hall &amp;amp; John Oates&lt;/h3&gt;

&lt;p&gt;I&amp;rsquo;m just old enough to remember roller rinks. My older brother and I would go,
and I have vivid memories of how &lt;em&gt;cool&lt;/em&gt; it felt to be in that dark, cavernous
room, surrounded by pulsing sound.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Maneater&amp;rdquo; is one of the songs I remember from there. (&amp;ldquo;Mickey&amp;rdquo; is another.) It
ticks almost every checkbox for what I still love in a song: tons of reverb,
high string pads, machine-precision drums, rhythmic bassline locked to a minor
chord progression. I know I should hear 80s cheese when I listen to it today,
but it still sounds just as spacious and moody today as it did then.&lt;/p&gt;

&lt;p&gt;What I also remember is strapping on my skates every time and never &lt;em&gt;once&lt;/em&gt;
having the courage to venture off the carpet onto the rink. It took me thirty
years and a friend&amp;rsquo;s skating party to face that fear and finally get out there.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=0R6WIbx8ysE&quot;&gt;Send Me an Angel&lt;/a&gt;&lt;/strong&gt; - Real Life&lt;/h3&gt;

&lt;p&gt;Alright, I gotta speed this up if we&amp;rsquo;re going to get through all forty in a
reasonable amount of time. There is a special place in the dark&amp;ndash;of course it&amp;rsquo;s
dark&amp;ndash;corner of my soul for sad synthpop. I don&amp;rsquo;t know what it is, but slap some
maudlin lyrics on top of a dance beat and I&amp;rsquo;m all over it. Fast + sad is my jam.&lt;/p&gt;

&lt;p&gt;The whole genre pushes my buttons, but &amp;ldquo;Send Me an Angel&amp;rdquo; stands out because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;David Sterry really goes for it lyrically. It&amp;rsquo;s hard to top &amp;ldquo;if a girl walks
up and carves her name in my heart, I&amp;rsquo;ll turn and run away&amp;rdquo; for abject
pathos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That little synth choir melody is six notes of absolute perfection.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Decades later, I was at a show for a friend of a friend&amp;rsquo;s band. The singer said
they were going to do a weird cover and if anyone knew the song, to shout out
the name of the band. He played the first three notes of that melody and it was
like the heavens opened above, presumably so angels could watch me yelling &amp;ldquo;Real
Life!&amp;rdquo; over and over at the top of my lungs like an idiot.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=m0AKJMGxwpE&quot;&gt;Enjoy the Silence&lt;/a&gt;&lt;/strong&gt; - Depeche Mode&lt;/h3&gt;

&lt;p&gt;Speaking of synthpop songs with aching melodies. I&amp;rsquo;ve listened to Depeche Mode
so much over the years that they are all over my memories. But the best, the
one I&amp;rsquo;ve shared with literally no one until now&amp;hellip;&lt;/p&gt;

&lt;p&gt;My best friend in elementary school had an older sister. My friend and were two
total nerds (still are), but his sister was &lt;em&gt;so cool&lt;/em&gt;&amp;ndash;serious and artistic.
Exhibit A: giant Depeche Mode posters on her wall. Exhibit B: a complete and
utter disinterest in interacting with us for even a second. At that age, that
was about all it took for a crush to blossom.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Cv6tuzHUuuk&quot;&gt;Walk Like an Egyptian&lt;/a&gt;&lt;/strong&gt; - Bangles&lt;/h3&gt;

&lt;p&gt;At some point in my childhood, I informed my parents that I liked music and
desired the ability to listen to it in my bedroom. My Dad, being the music snob
he is, solved that problem by buying young me an honest-to-God record player. No
cassette tapes in this household, young man!&lt;/p&gt;

&lt;p&gt;One of the first records I got was &amp;ldquo;Different Light&amp;rdquo; by the Bangles. I spent a
lot of time listening to the bassline in this song, gazing at the photos on the
cover, and having thoughts about Susanna Hoffs I wasn&amp;rsquo;t quite old enough to
process yet.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://youtu.be/vsQrKZcYtqg?t=6&quot;&gt;Istanbul (Not Constantinople)&lt;/a&gt;&lt;/strong&gt; - They Might Be Giants&lt;/h3&gt;

&lt;p&gt;Look, I don&amp;rsquo;t know what happened. I&amp;rsquo;ll blame it on incredible middle school
awkwardness, but I went through a phase where I, I shit you not, listened to
&lt;em&gt;nothing&lt;/em&gt; but TMBG. For like two years. I still know all of the lyrics to every
single song on &amp;ldquo;Flood&amp;rdquo;, &amp;ldquo;Lincoln&amp;rdquo;, &amp;ldquo;Apollo 18&amp;rdquo;, and &amp;ldquo;John Henry&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;They aren&amp;rsquo;t my thing very much these days, but the lyrics are still up there in
the wetware should a particularly odd karaoke night have need of them.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=EbI0cMyyw_M&quot;&gt;Run Through the Jungle&lt;/a&gt;&lt;/strong&gt; - CCR&lt;/h3&gt;

&lt;p&gt;I mentioned intros, right? This is another of the greats. I think most people
like the happy-dumb CCR hits, but for me I want the ones that remind me that the
US was goin&amp;rsquo; through some &lt;em&gt;shit&lt;/em&gt; when those songs came out. This tops that list.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=9muzyOd4Lh8&quot;&gt;Nights in White Satin&lt;/a&gt;&lt;/strong&gt; - Moody Blues&lt;/h3&gt;

&lt;p&gt;One of the things I truly lament about my generation and the generations to
follow is our acute self-awareness. Ironic detachment of the 90s followed by
&lt;a href=&quot;https://en.wikipedia.org/wiki/New_Sincerity&quot;&gt;ironic &lt;em&gt;attachment&lt;/em&gt;&lt;/a&gt; left us
basically unable to produce art without constantly obsessing about what the art
says about the artist.&lt;/p&gt;

&lt;p&gt;Can you imagine &lt;em&gt;anyone&lt;/em&gt; today sitting down to record a rock album with an
orchestra, and then slapping a &lt;em&gt;poem&lt;/em&gt; on the end? And doing it with complete,
heartfelt, unironic sincerity? It&amp;rsquo;s an ability that seems to be completely lost.&lt;/p&gt;

&lt;p&gt;Thankfully, this song embedded itself in my subconscious before that cultural
shift happened. I love every single bit of this song, completely, totally.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=I_izvAbhExY&quot;&gt;Stayin&amp;rsquo; Alive&lt;/a&gt;&lt;/strong&gt; - The Bee-Gees&lt;/h3&gt;

&lt;p&gt;Speaking of things I love un-ironically. For a nerdy white dude, I have spent a
surprisingly large amount of time shaking my ass on various dancefloors across
the United States. Not with any particular &lt;em&gt;skill&lt;/em&gt; mind you, but with
great enthusiasm.&lt;/p&gt;

&lt;p&gt;I like basically any kind of dance music, and disco is certainly on that list.
The genre is a distillation of everything that makes a song danceworthy, with
everything unnecessary filtered out. Picking one disco song is hard, and picking
one played by white guys is a borderline travesty, but I&amp;rsquo;d be lying if I said I
didn&amp;rsquo;t know every single cymbal crash in this song and had my arm thrust, finger
extended, for each.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=gzoEK545j64&quot;&gt;Groove is in the Heart&lt;/a&gt;&lt;/strong&gt; - Deee-Lite&lt;/h3&gt;

&lt;p&gt;Bootsy&amp;rsquo;s bassline. That beat. If this don&amp;rsquo;t get your booty movin&amp;rsquo;, your booty
must be dead.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=1lWJXDG2i0A&quot;&gt;Free Fallin&amp;rsquo;&lt;/a&gt;&lt;/strong&gt; - Tom Petty&lt;/h3&gt;

&lt;p&gt;Thomas Earl Petty is another one like Depeche Mode where it&amp;rsquo;s hard to know where
to slot him in. His music is a constant companion in my life. Narrowing his
presence on this list down to a single song was hard enough. &amp;ldquo;You Wreck Me&amp;rdquo;,
&amp;ldquo;Learning to Fly&amp;rdquo;, &amp;ldquo;American Girl&amp;rdquo;, &amp;ldquo;Breakdown&amp;rdquo; are all strong contenders.&lt;/p&gt;

&lt;p&gt;I picked this one because it spans what I think of as the two sides of Petty &amp;ndash;
the straightforward timeless American rock, and the bittersweet character
studies.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=hwZNL7QVJjE&quot;&gt;Stand By Me&lt;/a&gt;&lt;/strong&gt; - Ben E. King&lt;/h3&gt;

&lt;p&gt;A high school friend got a cheap acoustic guitar and I eventually got my hands
on it. Tinkering around, I figured out the bassline to &amp;ldquo;Stand By Me&amp;rdquo;, playing
that guitar like a bass, upside down. (I&amp;rsquo;m left-handed and it was strung
right-handed.) This was the first bassline I ever learned.&lt;/p&gt;

&lt;p&gt;Did you know King never intended to record this? He wrote it for the Drifters
and only reluctantly recorded it himself when he had some extra time in the
studio. Listen to that vocal performance. Can you imagine being so good that you
can just toss something like that out there?&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=CC5ca6Hsb2Q&quot;&gt;Children&lt;/a&gt;&lt;/strong&gt; - Robert Miles&lt;/h3&gt;

&lt;p&gt;Apparently, there was a whole house and techno scene going on in the world.
Maybe if I&amp;rsquo;d been a kid in Chicago or Detroit, I would have noticed. But none of
that made its way to southern Louisiana until this instrumental, piano-driven
electronica song improbably came down from space and landed on commercial radio.&lt;/p&gt;

&lt;p&gt;The first time I heard this song was a &lt;em&gt;revelation&lt;/em&gt;. I didn&amp;rsquo;t even know music
like this existed. I loved everything about it, the rigid tempo, heartbeat kick,
offset bass, heart-stirring melody. I couldn&amp;rsquo;t get enough.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=brZ_WBEzw6E&quot;&gt;Dark + Long (Dark Train)&lt;/a&gt;&lt;/strong&gt; - Underworld&lt;/h3&gt;

&lt;p&gt;Right around this time, I met a guy at work who wore these weird pants &lt;a href=&quot;https://www.google.com/search?q=jnco&amp;client=firefox-b-1-ab&amp;source=lnms&amp;tbm=isch&amp;sa=X&amp;ved=0ahUKEwim2dT2j4zbAhVOyWMKHfZZDaMQ_AUICigB&amp;biw=1166&amp;bih=803&quot;&gt;with
huge legs&lt;/a&gt;. What was that about? He told my brother and I he was a &amp;ldquo;raver&amp;rdquo;
and there was this music called &amp;ldquo;techno&amp;rdquo; and you could hear it at these things
called &amp;ldquo;raves&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;In one sitting, he gave us a rundown of artists that kept my ears full for
several years. The band that I forged the strongest bond with is Underworld. I
rushed out and got the &amp;ldquo;Pearl&amp;rsquo;s Girl&amp;rdquo; EP, then later &amp;ldquo;Dubnobasswithmyheadman&amp;rdquo;
and &amp;ldquo;Second Toughest in the Infants&amp;rdquo;. Eventually, I had almost everything they
ever recorded.&lt;/p&gt;

&lt;p&gt;I met some of my closest college friends by bonding over Underworld. We once
drove 900 miles from Baton Rouge to Chicago, non-stop, because that was the
closest place to us that Underworld was playing during the &amp;ldquo;Beaucoup Fish&amp;rdquo; tour.
Still one of the best shows I ever saw.&lt;/p&gt;

&lt;p&gt;Picking a single Underworld song is hard. Picking this particular song is
frustrating because for most, it&amp;rsquo;s associated with Trainspotting. But that&amp;rsquo;s not
what I think when I hear this. To me, it&amp;rsquo;s driving home from raves at the State
Palace Theatre in New Orleans as the sun comes up in our rearview mirror.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=bV-hSgL1R74&quot;&gt;Halcyon + On + On&lt;/a&gt;&lt;/strong&gt; - Orbital&lt;/h3&gt;

&lt;p&gt;A lot of techno at the 90s was, well, kind of dumb. Maybe a good beat to dance
to, but it didn&amp;rsquo;t leave you thinking or feeling much of anything. Aphex Twin
took care of the &amp;ldquo;thinking&amp;rdquo; part. Orbital took care of feeling. They showed that
music made with computers could have as much heart as anything else.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not the kind of person to fret about what song I want played at my funeral,
but if I had to pick, this might be it.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=WQYsGWh_vpE&quot;&gt;Roads&lt;/a&gt;&lt;/strong&gt; - Portishead&lt;/h3&gt;

&lt;p&gt;Oh, the tremolo on the Rhodes, mirroring Beth Gibbons&amp;rsquo; vibrato. Those ghost hits
on the snare. The strings. &lt;em&gt;That bassline.&lt;/em&gt; Every ounce of this is flawless.&lt;/p&gt;

&lt;p&gt;Like most people at the time, I got into trip-hop. Some of it doesn&amp;rsquo;t hold up,
but some of it, like this, I seem to respond to more and more the older I get.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=tSRYvYN1ayw&quot;&gt;Gorecki&lt;/a&gt;&lt;/strong&gt; - Lamb&lt;/h3&gt;

&lt;p&gt;Around this time, I was working at an Internet start-up during the first dotcom
bubble. Amazon had just started selling CDs and they had this new &amp;ldquo;Customers who
bought this also bought&amp;rdquo; thing. Today, we are inundated with machine learning
that knows every single connection between ever human artifact every produced.
It&amp;rsquo;s hard to remember what the world was before recommendation engines.&lt;/p&gt;

&lt;p&gt;But there was a time where if you liked some song, you might be totally unable
to find other stuff like it, &lt;em&gt;even if that other stuff existed.&lt;/em&gt; If you were
lucky, the guy at the music store knew stuff. That was literally it.&lt;/p&gt;

&lt;p&gt;So when I typed in the one trip-hop band I knew into the search box at
www.amazon.com, and then saw a list of other bands I might also like, and other
bands linked to from &lt;em&gt;them&lt;/em&gt;, and so on, it was like the gates to Paradise had
opened up.&lt;/p&gt;

&lt;p&gt;I ordered a stack of CDs, the largest music purchase of my life. They showed up
a week later. I took them home, put Lamb&amp;rsquo;s debut album in, and put on my
headphones. The first time this song came on, I was moved nearly to tears.&lt;/p&gt;

&lt;p&gt;Granted, I was going through some girlfriend stuff at the time, so tears weren&amp;rsquo;t
as far away as usual, but it&amp;rsquo;s still the most profoundly emotional listening
experience of my life.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=U4U19zwFENs&quot;&gt;La Femme d&amp;#39;Argent&lt;/a&gt;&lt;/strong&gt; - Air&lt;/h3&gt;

&lt;p&gt;One day, the roommate of the girl that caused the aforementioned troubles put in
a CD in her car stereo. She said, &amp;ldquo;You like electronic stuff, you might like
this.&amp;rdquo; I was totally flummoxed by what came on. It sounded like it had been
recorded in the 70s. Was it even &amp;ldquo;electronic&amp;rdquo; music? She insisted it had come
out recently. I&amp;rsquo;d never heard anything like it. It was, and still is,
magnificent. An album that stands outside of time and genre.&lt;/p&gt;

&lt;p&gt;Much much later, it occurred to me that I had dated the wrong roommate.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Ci_LIavsEhQ&quot;&gt;Kathy&amp;rsquo;s Song&lt;/a&gt;&lt;/strong&gt; - Apoptygma Berzerk&lt;/h3&gt;

&lt;p&gt;I love this song first because it reminds me of discovering a whole new genre of
music (synthpop and EBM), a circle of friends (&amp;ldquo;the Baton Rouge goth community&amp;rdquo;
as my friend used to say) and a new bar (The Spanish Moon) all at the same time.&lt;/p&gt;

&lt;p&gt;Going to that bar led to throwing parties with the same people and music, which
led to me DJing at our house, which eventually led to me DJing at the Spanish
Moon, which was a huge step for me to get past some of my crippling shyness.&lt;/p&gt;

&lt;p&gt;I love this song second because my sister-in-law&amp;rsquo;s name is &amp;ldquo;Cathy&amp;rdquo;, and I played
this at her wedding to my brother on the day that I got to officially call her
family.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=hpji_vmCUVU&quot;&gt;Remember (Mood II Swing Mix)&lt;/a&gt;&lt;/strong&gt; - BT&lt;/h3&gt;

&lt;p&gt;There are a number of BT songs that could be on this list, but I picked this
remix because it&amp;rsquo;s the track I&amp;rsquo;ve listened to the most over the years. &amp;ldquo;Flaming
June&amp;rdquo; and &amp;ldquo;Poseidon&amp;rdquo; are up there too.&lt;/p&gt;

&lt;p&gt;But, also, because every time I hear that little fuzz effect come in at :15, I
can still perfectly picture the owner of The Spanish Moon sprinting across the
dancefloor towards the DJ booth, panic in his eyes, because he thought I&amp;rsquo;d blown
his sound system.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=sbnujaAbD2A&quot;&gt;Autumn Tactics&lt;/a&gt;&lt;/strong&gt; - Chicane&lt;/h3&gt;

&lt;p&gt;That couple year span when &amp;ldquo;progressive house&amp;rdquo; was the thing brought a lot of
great artists to my attention. Of all of them, I probably sunk more time into
Chicane&amp;rsquo;s first two albums than anything else. This isn&amp;rsquo;t really a house track
&amp;ndash; I don&amp;rsquo;t know how to categorize it, honestly &amp;ndash; and maybe that&amp;rsquo;s why it&amp;rsquo;s
held up so well for me. I&amp;rsquo;ve been listening to it for close to twenty years, and
I still haven&amp;rsquo;t tired of it.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=B4px0qQrG5E&quot;&gt;Poor Leno&lt;/a&gt;&lt;/strong&gt; - Röyksopp&lt;/h3&gt;

&lt;p&gt;We&amp;rsquo;re getting closer to the modern era, witnessed by the fact that I stumbled
onto this song from a &lt;em&gt;video&lt;/em&gt; on the &lt;em&gt;Internet&lt;/em&gt;. This song led to me buying
turntables. I was going to clubs listening to house all the time, but most of
the DJs were playing stripped down tribal or tech house that sounded soulless
and empty to me. I didn&amp;rsquo;t necessarily need a full set of lyrics, but I at least
wanted a chord progression.&lt;/p&gt;

&lt;p&gt;I realized that if I ever wanted to hear this track or others like it on a
dancefloor, I was going to have to make it happen myself. I filled up my online
shopping cart at Turntable Lab. A few weeks later some very large, very heavy
boxes showed up at work, and I was off learning how to beatmatch.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=omJQVvKVQCk&quot;&gt;Tracey In My Room&lt;/a&gt;&lt;/strong&gt; - EBTG vs Soul Vision&lt;/h3&gt;

&lt;p&gt;This song is a two-fer. Tracy Thorn from Everything but the Girl is one of my
favorite vocalists. When Ben Watt took EBTG in a decidedly electronic direction
with &amp;ldquo;Walking Wounded&amp;rdquo; and then &amp;ldquo;Temperamental&amp;rdquo;, I was right there with him.&lt;/p&gt;

&lt;p&gt;But around this time was also when I started to get fully into house music, the
more heartfelt the better. This record, a mash-up of a house song and the vocals
from &amp;ldquo;Wrong&amp;rdquo; merges those two better than it has any right to.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=5ViItcZyYBw&quot;&gt;Unspoken&lt;/a&gt;&lt;/strong&gt; - Four Tet&lt;/h3&gt;

&lt;p&gt;In my twenties, my friends and I used to hit &lt;a href=&quot;http://parkavecds.com/&quot;&gt;Park Ave.
CDs&lt;/a&gt; every Tuesday when new music came out. This album
was at a listening station on an end cap. When the first song came on, it was as
if the lights in the building gradually dimmed, leaving nothing but sound.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mMh-Y2IWJZc&quot;&gt;Back of my Hand&lt;/a&gt;&lt;/strong&gt; - Gemma Hayes&lt;/h3&gt;

&lt;p&gt;We went to this record store so often that the employees would hook us up with
samplers and other merch. This song was on one. It&amp;rsquo;s not my usual genre and I
can&amp;rsquo;t say I&amp;rsquo;ve listened to much else by her. But the production on this song
pushes it out of generic singer-songwriter and into something really interesting
to me.&lt;/p&gt;

&lt;p&gt;I love the contrast between the folksy guitar &amp;ndash; twelve-string? double-tracked?
&amp;ndash; and that that tinny mechanical drum loop. When the fully-EQed beat and organ
drops, my heart goes a-flutter.&lt;/p&gt;

&lt;p&gt;I had this song as my alarm clock for several years. It was a gentle way to wake
up and the end result was the lyrics embedding themselves in my subconscious.
Years later, my kids started asking me to sing them bedtime songs. This was one
of the few whose words I remembered and whose melody fit within my not-so-wide
vocal range.&lt;/p&gt;

&lt;p&gt;Listening brings back peaceful mornings sipping coffee in Orlando, and gentle
nights in Washington stroking my daughters&amp;rsquo; hair as they fall asleep. It&amp;rsquo;s hard
to imagine a better pair of bookends.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=0wrsZog8qXg&quot;&gt;Such Great Heights&lt;/a&gt;&lt;/strong&gt; - Postal Service&lt;/h3&gt;

&lt;p&gt;The drag about being into electronic music in Orlando back then was, well, the
other people into it. Instead of the fun rave scene of New Orleans where kids
were down to Earth and just wanted a good time, Orlando was a &lt;em&gt;club&lt;/em&gt; scene &amp;ndash;
overdressed bros and over-made-up woman desperately trying to impress each other
while trying not to look desperate.&lt;/p&gt;

&lt;p&gt;Indie dance music and Orlando&amp;rsquo;s Independent Bar (called &amp;ldquo;Barbarella&amp;rdquo; at the
time) saved me from that. The indie night there remains the absolute best
dancefloor, and the most fun crowd I&amp;rsquo;ve ever experienced. Like clockwork, every
Friday night ended with a packed, sweaty, grinning mass of euphoric people.&lt;/p&gt;

&lt;p&gt;There are a number of songs I could pick to be the anthem for that time in my
life, but this one also happens to mark a great point in a relationship (before
the relationship went no-so-great).&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=SPlQpGeTbIE&quot;&gt;Move Your Feet&lt;/a&gt;&lt;/strong&gt; - Junior Senior&lt;/h3&gt;

&lt;p&gt;One of the few things I love as much as dance music is pixel art, so this song&amp;rsquo;s
video pushes all of the buttons on the 747 control panel of my heart.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Gs069dndIYk&quot;&gt;September&lt;/a&gt;&lt;/strong&gt; - Earth, Wind, and Fire&lt;/h3&gt;

&lt;p&gt;I expected more soul music to make this list, but somehow it didn&amp;rsquo;t. It would
have been a real shame to omit this gem. Thursdays were soul night at I-Bar and
I can&amp;rsquo;t hear this song without picturing my friend Amy cutting up the
dancefloor.&lt;/p&gt;

&lt;p&gt;This song gets twice my love because I also used to spin the fantastic &lt;a href=&quot;https://www.youtube.com/watch?v=wn5Q37qOiiA&quot;&gt;Phats &amp;amp;
Small house remix&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=g6jhpaX7fNQ&quot;&gt;Under the Milky Way&lt;/a&gt;&lt;/strong&gt; - The Church&lt;/h3&gt;

&lt;p&gt;You know those songs that reside in a primordial part of your brain? I can&amp;rsquo;t
recall ever &lt;em&gt;not&lt;/em&gt; knowing this song. I&amp;rsquo;m wired towards the low end of the
frequency spectrum. I play bass, and tend to focus on the bass and rhythm side
of songs. That extends to vocals. I can&amp;rsquo;t do histrionic screechy singers.
Nothing sets my soul at ease quite like a soft baritone.&lt;/p&gt;

&lt;p&gt;This is another song I used to sing to my kids as they fell asleep.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2q9_ZEtuTR8&quot;&gt;Maybe Tomorrow&lt;/a&gt;&lt;/strong&gt; - Stereophonics&lt;/h3&gt;

&lt;p&gt;The beginning of the video for this song is a dirty lie. This song wasn&amp;rsquo;t
crafted by imperfect human hands. It was plucked, flawless, from some sonic vein
deep within the Earth.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=BiPLOmTp6IA&quot;&gt;Stop&lt;/a&gt;&lt;/strong&gt; - Black Rebel Motorcycle Club&lt;/h3&gt;

&lt;p&gt;Hanging out at Independent Bar opened one of the most fulfilling chapters of my
life. It was there that I met my friend Mikey, which led to us starting a band.
Playing music with others was a transcendent experiences &amp;ndash; to hear four people
produce one single harmonious sound. To give birth to something better than we
could have made on our own. Being on stage is a bonus. Just to play is the
thing.&lt;/p&gt;

&lt;p&gt;My bandmates introduced me to a lot of great rock, including BRMC. I used to
listen to this track on the way to shows and by the time I got to the gig, that
bassline had me feeling like I could walk through a brick wall.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=MYYG1lAUntM&quot;&gt;Baby in Two&lt;/a&gt;&lt;/strong&gt; - Pernice Brothers&lt;/h3&gt;

&lt;p&gt;My drummer Shannon introduced me to Pernice Brothers. Our band days are over, we
live about three thousand miles apart, but he will always be my drummer and I
will always be his bassist. There&amp;rsquo;s a special kind of love that forms only
between two halves of a rhythm section and this album is the soundtrack to mine.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=S28tILqie1o&quot;&gt;Cupid&lt;/a&gt;&lt;/strong&gt; - Sam Cooke&lt;/h3&gt;

&lt;p&gt;God, did they know how to record back then. Take one of the world&amp;rsquo;s greatest
voices. Add beautiful, authentic reverb, and just enough tape saturation, and
you get a sound so rich I can practically taste it.&lt;/p&gt;

&lt;p&gt;But the technical merits are an aside. The real reason this is here is because
it marks the time when I met my wife. This song is inseparable from her,
from &lt;em&gt;us&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=L5dUsZ4Djd0&quot;&gt;Blue Ridge Mountains&lt;/a&gt;&lt;/strong&gt; - Fleet Foxes&lt;/h3&gt;

&lt;p&gt;By this time, I was burned out from eight years in the game industry. Tired
of the heat and &lt;em&gt;sameness&lt;/em&gt; Florida&amp;ndash;every month indistinguishable from the
previous, the days an unending blur of sunlight.&lt;/p&gt;

&lt;p&gt;My wife and I discovered the Pacific Northwest on a work trip. We played this
album non-stop during our honeymoon on the Olympic Peninsula, and by the end we
were ready to uproot and move. Back in Florida, during the months it took for me
to find work in Seattle, this record was a constant reminder of the promise
awaiting us out west.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=NDHY1D0tKRA&quot;&gt;I Will Follow You Into the Dark&lt;/a&gt;&lt;/strong&gt; - Death Cab for Cutie&lt;/h3&gt;

&lt;p&gt;There is a Seattle city ordinance that you must like Ben Gibbard.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=3mUfOs-CTCw&quot;&gt;Shooting Stars&lt;/a&gt;&lt;/strong&gt; - Bag Raiders&lt;/h3&gt;

&lt;p&gt;My love of disco and house naturally turned into a love of nu-disco. I don&amp;rsquo;t
know what&amp;rsquo;s going on in Australia, but there&amp;rsquo;s a whole pile of bands out of
Sydney and Melbourne that sound like they took everything I love about the 70s
and 80s, mashed it all together, and somehow made it sound fresh again.&lt;/p&gt;

&lt;p&gt;One of the joys of being a Dad is playing music with my kids. I get to choose
the songs that will form their subconscious musical memory. They love this
album, perhaps largely because I used to pick them up and dance with them in the
kitchen every time we played it. I hope when they are much older and hear this,
they still think of me.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=7HPMK9Uxq3I&quot;&gt;Elevate&lt;/a&gt;&lt;/strong&gt; - St. Lucia&lt;/h3&gt;

&lt;p&gt;Like I said, the 80s is new again. I won&amp;rsquo;t lie. Listening to music that apes a
genre that I still remember the first time it came around makes me feel pretty
old. That weird cringe I get when I see fashion come full circle and the young
folk start wearing stuff I still have jammed in the back of my closet.&lt;/p&gt;

&lt;p&gt;I try to ignore that twinge because, honestly, St. Lucia is fantastic. This
isn&amp;rsquo;t some ironic winking aping of the past (looking at you The Darkness and
Steel Panther). St. Lucia is a gushing love letter to everything great about
beachy 80s pop. It&amp;rsquo;s mai tais, sand between your toes, coconut sunscreen.
Endless summer and eternal youth.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ImKY6TZEyrI&quot;&gt;Fade Into You&lt;/a&gt;&lt;/strong&gt; - Mazzy Star&lt;/h3&gt;

&lt;p&gt;We&amp;rsquo;re nearing the end of the list, nearly through forty years of living and
listening. It&amp;rsquo;s been a long drive down a winding road, and the sun will be up
soon.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=xzQvGz6_fvA&quot;&gt;I&amp;rsquo;m on Fire&lt;/a&gt;&lt;/strong&gt; - Bruce Springsteen&lt;/h3&gt;

&lt;p&gt;Forty feels like all my younger selves are lost, receded far into the past. Yet,
at the same time, they still burn vibrantly alive inside, refusing to be
forgotten.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2016/06/16/long-names-are-long</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2016/06/16/long-names-are-long"/>
    <title>Long Names Are Long</title>
    <published>2016-06-16T00:00:00-07:00</published>
    <updated>2016-06-16T00:00:00-07:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;p&gt;One smart thing Google does is rigorous code reviews. Every change, before you
can land it, gets reviewed in at least two way. First, someone on the team does
a normal review to make sure the code does what it&amp;rsquo;s supposed to.&lt;/p&gt;

&lt;p&gt;But, then, there&amp;rsquo;s a second layer of review called &lt;em&gt;readability&lt;/em&gt;. It makes sure
the code is, well, readable: Is it easy to understand and maintain? Does it
follow the style and idioms of the language? Is it well-documented?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.dartlang.org/&quot;&gt;Dart&lt;/a&gt; usage inside Google is cranking up, so I&amp;rsquo;ve been doing a long ton of
these kind of code reviews. As a language designer, it&amp;rsquo;s fascinating. I get a
first-hand view into how people use Dart, which is really useful for evolving
it. I have a clearer picture of which mistakes are common and which features are
heavily used. I feel like an ethnographer journaling the lives of natives.&lt;/p&gt;

&lt;p&gt;But, anyway, that&amp;rsquo;s not what this is about. Heck, it&amp;rsquo;s not even about Dart. What
I want to talk about is something I see in a lot of code that drives me up the
wall: &lt;strong&gt;identifiers that are too damn long.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, names can be too short. Back when C only required external identifiers to
be unique up to the first six characters; auto-complete hadn&amp;rsquo;t been invented;
and every keypress had to be made uphill, in the snow, both ways; it was a
problem. I&amp;rsquo;m glad we now live in a futuristic utopia where keyboard farts like
&lt;code&gt;p&lt;/code&gt;, &lt;code&gt;idxcrpm&lt;/code&gt;, and &lt;code&gt;x3&lt;/code&gt; are rare.&lt;/p&gt;

&lt;p&gt;But the pendulum has swung too far in the other direction. We shouldn&amp;rsquo;t be
Hemingway, but we don&amp;rsquo;t need to be Tennessee Williams either. Very &lt;em&gt;long&lt;/em&gt; names
also hurt the clarity of the code where they are used. Giant identifiers dwarf
the operations you&amp;rsquo;re performing on them, are hard to visually scan, and force
extra line breaks which interrupt the flow of the code.&lt;/p&gt;

&lt;p&gt;Long class names discourage users from declaring variables of that type, leading
to massive, gnarly nested expressions instead of hoisting things out to locals.
Long method names obscure their equally important argument lists. Long variables
are annoying to use repeatedly, leading to sprawling method chains or cascades.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve seen identifiers over 60 characters long. You could fit a haiku or a koan
in there (and likely enlighten the reader more than the actual chosen name did).
Fear not, I am here to help.&lt;/p&gt;

&lt;h2&gt;Choosing a Good Name&lt;/h2&gt;

&lt;p&gt;A name has two goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It needs to be &lt;em&gt;clear&lt;/em&gt;: you need to know what the name refers to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It needs to be &lt;em&gt;precise&lt;/em&gt;: you need to know what it does &lt;em&gt;not&lt;/em&gt; refer to.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a name has accomplished those goals, any additional characters are dead
weight. Here&amp;rsquo;s some guidelines I use when I names things in my code:&lt;/p&gt;

&lt;h3&gt;1. Omit words that are obvious given a variable&amp;rsquo;s or parameter&amp;rsquo;s type&lt;/h3&gt;

&lt;p&gt;If your language has a static type system, users usually know the type of a
variable. Methods tend to be short, so even when looking at local variable whose
type was inferred, or in a code review or some place where static analysis isn&amp;rsquo;t
available, it rarely takes more than scanning a few lines to tell what type a
variable has.&lt;/p&gt;

&lt;p&gt;Given that, it&amp;rsquo;s redundant to put the type in the variable&amp;rsquo;s name. We have
rightfully abandoned &lt;a href=&quot;https://en.wikipedia.org/wiki/Hungarian_notation&quot;&gt;Hungarian notation&lt;/a&gt;. &lt;em&gt;Let it go.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Bad:&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nameString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;DockableModelessWindow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dockableModelessWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Better:&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;DockableModelessWindow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In particular, for collections, it&amp;rsquo;s almost always better to just use a plural
noun describing the &lt;em&gt;contents&lt;/em&gt; instead of a singular noun describing the
&lt;em&gt;collection&lt;/em&gt;. If the reader cares more about what&amp;rsquo;s &lt;em&gt;in&lt;/em&gt; the collection, the
name should reflect that.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Bad:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;holidayDateList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employeeRoleHashMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Better:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;holidays&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employeeRoles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This also applies to method names. The method name doesn&amp;rsquo;t need to describe its
parameters or their types&amp;mdash;the parameter list does that for you.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Bad:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mergeTableCells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TableCell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sortEventsUsingComparator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Comparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Better:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TableCell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Comparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This tends to make callsites read better:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mergeTableCells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tableCells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sortEventsUsingComparator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Is it just me, or is there an echo echo in here here?&lt;/p&gt;

&lt;h3&gt;2. Omit words that don&amp;rsquo;t disambiguate the name&lt;/h3&gt;

&lt;p&gt;Some people tend to cram everything they know about something into its name.
Remember, the name is an &lt;em&gt;identifier&lt;/em&gt;: it points you to &lt;em&gt;where&lt;/em&gt; it&amp;rsquo;s defined.
It&amp;rsquo;s not an exhaustive catalog of everything the reader could want to know about
the object. The definition does that. The name just gets them there.&lt;/p&gt;

&lt;p&gt;When I see an identifier like &lt;code&gt;recentlyUpdatedAnnualSalesBid&lt;/code&gt;, I ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Are there updated annual sales bids that aren&amp;rsquo;t recent?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are there recent annual sales bids that were not updated?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are there recently updated sales bids that aren&amp;rsquo;t annual?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are there recently updated annual bids not related to sales?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are there recently updated annual sales things that are not bids?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &amp;ldquo;no&amp;rdquo; for any of these usually points to an extraneous word.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Bad:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;finalBattleMostDangerousBossMonster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weaklingFirstEncounterMonster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Better:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;boss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;firstMonster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course, you can go too far. Shortening that first example to &lt;code&gt;bid&lt;/code&gt; might be a
little &lt;em&gt;too&lt;/em&gt; vague. But, when in doubt, leave it out. You can always add
qualifiers later if the name proves to cause a collision or be imprecise but
it&amp;rsquo;s unlikely you&amp;rsquo;ll come back later to trim the fat.&lt;/p&gt;

&lt;h3&gt;3. Omit words that are known from the surrounding context&lt;/h3&gt;

&lt;p&gt;I can use &amp;ldquo;I&amp;rdquo; in this paragraph because you can see this post is by Bob Nystrom.
My dumb face is right up there. I don&amp;rsquo;t need to keep saying “Bob Nystrom”
everywhere here (despite Bob Nystrom&amp;rsquo;s temptation to aggrandize Bob Nystrom by
doing so). Code works the same way. A method or field occurs in the context of a
class. A variable occurs in the context of a method. Take that context for
granted and don&amp;rsquo;t repeat it.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Bad:&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnualHolidaySale&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_annualSaleRebate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;promoteHolidaySale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Better:&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnualHolidaySale&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_rebate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;promote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In practice, this means that the more deeply nested a name is, the more surrounding context it has. That in turn means it usually has a shorter name. The effect is that identifiers with shorter scopes have shorter names.&lt;/p&gt;

&lt;h3&gt;4. Omit words that don&amp;rsquo;t mean much of anything&lt;/h3&gt;

&lt;p&gt;I used to see this a lot in the game industry. Some people succumb to the temptation to inflate their identifiers by adding Serious Business sounding words. I guess it makes their code feel more important and, by extension, makes &lt;em&gt;them&lt;/em&gt; feel more important.&lt;/p&gt;

&lt;p&gt;In many cases, the words carry no meaningful information. They&amp;rsquo;re just fluff or jargon. Usual suspects include: &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, &lt;code&gt;manager&lt;/code&gt;, &lt;code&gt;engine&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;entity&lt;/code&gt;, and &lt;code&gt;instance&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A good name paints a picture in the mind of the reader. Calling something a &amp;ldquo;manager&amp;rdquo; doesn&amp;rsquo;t convey any image to the reader about what the thing does. Does it do performance evaluations? Give raises?&lt;/p&gt;

&lt;p&gt;Ask yourself &amp;ldquo;Would this identifier mean the same thing if I removed the word?&amp;rdquo; If so, the word doesn&amp;rsquo;t carry its weight: vote if off the island.&lt;/p&gt;

&lt;h2&gt;Applying the Guidelines&amp;hellip; to Waffles&lt;/h2&gt;

&lt;p&gt;To give you a feel for how these rules work in practice, here&amp;rsquo;s an example that breaks all of these rules. This contrived example is heart-breakingly close to real code I&amp;rsquo;ve seen in reviews:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DeliciousBelgianWaffleObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;garnishDeliciousBelgianWaffleWithStrawberryList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strawberry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strawberryList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We know from the type that it takes a list of strawberries (#1), so let&amp;rsquo;s cut that out:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DeliciousBelgianWaffleObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;garnishDeliciousBelgianWaffle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strawberry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strawberries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unless our program has foul-tasting Belgian waffles, or waffles of other nationalities, we can drop those adjectives (#2):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaffleObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;garnishWaffle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strawberry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strawberries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The method is inside a &lt;code&gt;WaffleObject&lt;/code&gt;, so we know what it&amp;rsquo;s going to garnish (#3):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaffleObject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;garnish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strawberry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strawberries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Obviously it&amp;rsquo;s an object. Everything is an object. That&amp;rsquo;s kind of what &amp;ldquo;object-oriented&amp;rdquo; means (#4):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Waffle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;garnish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strawberry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strawberries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There, much better.&lt;/p&gt;

&lt;p&gt;I think these are pretty simple guidelines. You may think it&amp;rsquo;s pointless to worry about this stuff, but I believe that &lt;a href=&quot;/2009/06/05/naming-things-in-code/&quot;&gt;naming things&lt;/a&gt; is one of the most fundamental tasks we do when programming. Names are the structure we impose on the formless sea of bits that is computing.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2015/09/08/the-hardest-program-ive-ever-written</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2015/09/08/the-hardest-program-ive-ever-written"/>
    <title>The Hardest Program I've Ever Written</title>
    <published>2015-09-08T00:00:00-07:00</published>
    <updated>2015-09-08T00:00:00-07:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;style&gt;
.skull, .skull-note {
  border-radius: 4px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;

  background: hsl(35, 100%, 96%);
  color: hsl(35, 40%, 50%);

  padding: 1px;
}

.skull::before, .skull-note::before {
  content: &quot;\01f480&quot;;
  margin-right: -2px;
}

a.skull {
  position: relative;
  top: -0.4em;
  font-size: 80%;
}

a.skull:hover, a.skull-note:hover {
  color: hsl(35, 100%, 30%);
}
&lt;/style&gt;

&lt;p&gt;The hardest program I&amp;rsquo;ve ever written, once you strip out the whitespace, is
3,835 lines long. That handful of code took me almost a year to write. Granted,
that doesn&amp;rsquo;t take into account the code that didn&amp;rsquo;t make it. The &lt;a href=&quot;https://github.com/dart-lang/dart_style/commits/master&quot;&gt;commit
history&lt;/a&gt; shows that I deleted 20,704 lines of code over that time. Every
surviving line has about three fallen comrades.&lt;/p&gt;

&lt;p&gt;If it took that much thrashing to get it right, you&amp;rsquo;d expect it to do something
pretty deep right? Maybe a low-level hardware interface or some wicked graphics
demo with tons of math and pumping early-90s-style techno? A likely-to-turn-evil
machine learning AI Skynet thing?&lt;/p&gt;

&lt;p&gt;Nope. It reads in a string and writes out a string. The only difference between
the input and output strings is that it modifies some of the whitespace
characters. I&amp;rsquo;m talking, of course, about &lt;a href=&quot;https://github.com/dart-lang/dart_style&quot;&gt;an automated code
formatter&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Introducing dartfmt&lt;/h2&gt;

&lt;p&gt;I work on the &lt;a href=&quot;https://www.dartlang.org/&quot;&gt;Dart&lt;/a&gt; programming language. Part of my job is helping make more
Dart code, readable, idiomatic, and consistent, which is why I ended up writing
our &lt;a href=&quot;https://www.dartlang.org/articles/style-guide/&quot;&gt;style guide&lt;/a&gt;. That was a good first step, but any style guide written in
English is either so brief that it&amp;rsquo;s ambiguous, or so long that no one reads it.&lt;/p&gt;

&lt;p&gt;Go&amp;rsquo;s &lt;a href=&quot;https://golang.org/cmd/gofmt/&quot;&gt;&amp;ldquo;gofmt&amp;rdquo;&lt;/a&gt; tool showed a better solution: automatically format
everything. Code is easier to read and contribute to because it&amp;rsquo;s already in the
style you&amp;rsquo;re used to. Even if the output of the formatter isn&amp;rsquo;t great, it ends
those interminable soul-crushing arguments on code reviews about formatting.&lt;/p&gt;

&lt;p&gt;Of course, I still have to sell users on running the formatter in the first
place. For &lt;em&gt;that&lt;/em&gt;, having great output really does matter. Also, I&amp;rsquo;m pretty
picky with the formatting in my own code, and I didn&amp;rsquo;t want to tell users to use
a tool that I didn&amp;rsquo;t use myself.&lt;/p&gt;

&lt;p&gt;Getting that kind of quality means applying pretty sophisticated formatting
rules. That in turn makes &lt;em&gt;performance&lt;/em&gt; difficult. I knew balancing quality and
speed would be hard, but I didn&amp;rsquo;t realize just how deep the rabbit hole went.&lt;/p&gt;

&lt;p&gt;I have finally emerged back into the sun, and I&amp;rsquo;m pleased with what I brought
back. I like the output, and the performance is solid. On my laptop, it can blow
through over two million lines of code in about 45 seconds, using a single core.&lt;/p&gt;

&lt;h2&gt;Why is formatting hard?&lt;/h2&gt;

&lt;p&gt;At this point, you&amp;rsquo;re probably thinking, &amp;ldquo;Wait. What&amp;rsquo;s so hard about
formatting?&amp;rdquo; After you&amp;rsquo;ve parsed, can&amp;rsquo;t you just walk the &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;AST&lt;/a&gt; and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Prettyprint&quot;&gt;pretty-print&lt;/a&gt; it with some whitespace?&lt;/p&gt;

&lt;p&gt;If every statement fit within the column limit of the page, yup. It&amp;rsquo;s a piece of
cake. (I think that&amp;rsquo;s what gofmt does.) But our formatter also keeps your code
within the line length limit. That means adding line breaks (or &amp;ldquo;splits&amp;rdquo; as the
formatter calls them), and determining the best place to add those is &lt;a href=&quot;https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap#Knuth.27s_algorithm&quot;&gt;famously
hard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out this guy:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;experimentalBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;link&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;rel&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;import&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;href&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POLYMER_EXPERIMENTAL_HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are thirteen places where a line break is possible here according to our
style rules. That&amp;rsquo;s 8,192 different combinations if we brute force them all &lt;a
id=&quot;1&quot; href=&quot;#1-note&quot; class=&quot;skull&quot;&gt;1&lt;/a&gt;. The search space we have to cover is
&lt;em&gt;exponentially&lt;/em&gt; large, and even ranking different solutions is a subtle problem.
Is it better to split before the &lt;code&gt;.any()&lt;/code&gt;? Why or why not?&lt;/p&gt;

&lt;div class=&quot;update&quot;&gt;

&lt;p&gt;&lt;strong&gt;What is up with the skulls?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had two goals with this article: to explain how dartfmt works, and to show a realistic picture of how a real programmer solves a difficult problem with all of the messiness that entails. Alas, the first is more than long enough to try your patience, so I shunted all of the dead ends and failed attempts to footnotes. Click the skulls to laugh at my misfortune.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;In Dart, we made things harder on ourselves. We have anonymous functions, lots
of &lt;a href=&quot;https://api.dartlang.org/133511/dart-core/Iterable-class.html&quot;&gt;higher-order functions&lt;/a&gt;, and&amp;mdash;until we added &lt;a href=&quot;https://www.dartlang.org/articles/await-async/&quot;&gt;&lt;code&gt;async&lt;/code&gt; and
&lt;code&gt;await&lt;/code&gt;&lt;/a&gt;&amp;mdash;used &lt;a href=&quot;https://api.dartlang.org/1.12.1/dart-async/Future-class.html&quot;&gt;futures&lt;/a&gt; for concurrency. That means lots of
callbacks and lots of long method chains. Some Dart users really dig a
functional style and appear to be playing a game where whoever crams the most
work before a single semicolon wins.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s real code from an amateur player:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_bindAssignablePropsOn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bindAssignableProps&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propAndExp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propAndExp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jsNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propAndExp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yeah, that&amp;rsquo;s four nested functions. 1,048,576 ways to split that one. Here&amp;rsquo;s one
of the best that I&amp;rsquo;ve found. This is what a pro player brings to the game:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doughnutFryer&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_frostingGlazer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;_conveyorBelts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;sprinkleSprinkler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;sauceDripper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;catchError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cannotGetConveyorBeltRunning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tellEveryoneDonutsAreJustAboutDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;croissantFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;_giantBakingOvens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;butterbutterer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;catchError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_handleBakingFailures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scriptLoadingTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;onTimeout:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_handleBakingFailures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;catchError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cannotGetConveyorBeltRunning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;catchError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cannotGetConveyorBeltRunning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Let&amp;#39;s eat!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The funny names are because this was sanitized from internal code.) That&amp;rsquo;s a
&lt;em&gt;single&lt;/em&gt; statement, all 565 characters of it. There are about 549 &lt;em&gt;billion&lt;/em&gt; ways
we could line break it.&lt;/p&gt;

&lt;p&gt;Ultimately, this is what the formatter does. It applies some fairly
sophisticated ranking rules to find the best set of line breaks from an
exponential solution space. Note that &amp;ldquo;best&amp;rdquo; is a property of the &lt;em&gt;entire
statement&lt;/em&gt; being formatted. A line break changes the indentation of the
remainder of the statement, which in turn affects which other line breaks are
needed. Sorry, Knuth. No &lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic_programming&quot;&gt;dynamic programming&lt;/a&gt; this time &lt;a id=&quot;2&quot;
href=&quot;#2-note&quot; class=&quot;skull&quot;&gt;2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think the formatter does a good job, but &lt;em&gt;how&lt;/em&gt; it does it is a mystery to
users. People get spooked when robots surprise them, so I thought I would trace
the inner workings of its metal mind. And maybe try to justify to myself why it
took me a year to write a program whose behavior in many ways is
indistinguishable from &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;How the formatter sees your code&lt;/h2&gt;

&lt;p&gt;As you&amp;rsquo;d expect from a program that works on source code, the formatter is
structured much like a compiler. It has a &lt;a href=&quot;https://en.wikipedia.org/wiki/Compiler#Structure_of_a_compiler&quot;&gt;front end&lt;/a&gt; that parses your code
and converts that to an &lt;a href=&quot;https://en.wikipedia.org/wiki/Intermediate_language#Intermediate_representation&quot;&gt;intermediate representation&lt;/a&gt; &lt;a id=&quot;3&quot;
href=&quot;#3-note&quot; class=&quot;skull&quot;&gt;3&lt;/a&gt;. It does some optimization and clean up on
that &lt;a id=&quot;4&quot; href=&quot;#4-note&quot; class=&quot;skull&quot;&gt;4&lt;/a&gt;, and then the IR goes to a
back end &lt;a id=&quot;5&quot; href=&quot;#5-note&quot; class=&quot;skull&quot;&gt;5&lt;/a&gt; that produces the final
output. The main objects here are &lt;strong&gt;chunks&lt;/strong&gt;, &lt;strong&gt;rules&lt;/strong&gt;, and &lt;strong&gt;spans&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;Chunks&lt;/h3&gt;

&lt;p&gt;A &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/chunk.dart&quot;&gt;chunk&lt;/a&gt; is an atomic unit of formatting. It&amp;rsquo;s a contiguous region of
characters that we know will not contain any line breaks. Given this code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* comment */&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We break it into these chunks: &lt;code&gt;format&lt;/code&gt; &lt;code&gt;/* comment */&lt;/code&gt; &lt;code&gt;this;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Chunks are similar to a &lt;a href=&quot;https://en.wikipedia.org/wiki/Lexical_analysis#Token&quot;&gt;token&lt;/a&gt; in a conventional compiler, but they tend to
be, well, &lt;em&gt;chunkier&lt;/em&gt;. Often, the text for several tokens ends up in the same
chunk, like &lt;code&gt;this&lt;/code&gt; and &lt;code&gt;;&lt;/code&gt; here. If a line break can never occur between two
tokens, they end up in the same chunk &lt;a id=&quot;6&quot; href=&quot;#6-note&quot;
class=&quot;skull&quot;&gt;6&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Chunks are mostly linear. For example, given an expression like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nested&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ca&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We chunk it to the flat list: &lt;code&gt;some(&lt;/code&gt; &lt;code&gt;nested,&lt;/code&gt; &lt;code&gt;function(&lt;/code&gt; &lt;code&gt;ca +&lt;/code&gt; &lt;code&gt;ll))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could treat an entire source file like a single flat sequence of chunks, but
it would take forever and a day to line break the whole thing &lt;a id=&quot;7&quot;
href=&quot;#7-note&quot; class=&quot;skull&quot;&gt;7&lt;/a&gt;. With things like long chains of asynchronous
code, a single &amp;ldquo;statement&amp;rdquo; may be hundreds of lines of code containing several
nested functions or collections that each contain their own piles of code.&lt;/p&gt;

&lt;p&gt;We can&amp;rsquo;t treat those nested functions or collection literals entirely
independently because the surrounding expression affects how they are indented.
That in turn affects how long their lines are. Indent a function body two more
spaces and now its statements have two fewer spaces before they hit the end of
the line.&lt;/p&gt;

&lt;p&gt;Instead, we treat nested block bodies as a separate little list of chunks to be
formatted mostly on their own but subordinate to where they appear. The chunk
that begins one of these literals, like the &lt;code&gt;{&lt;/code&gt; preceding a function or map,
contains a list of child &lt;em&gt;block chunks&lt;/em&gt; for the contained block. In other words,
chunks do form a tree, but one that only reflects block nesting, not
expressions.&lt;/p&gt;

&lt;p&gt;The end of a chunk marks the point where a split may occur in the final output,
and the chunk has some data describing it &lt;a id=&quot;8&quot; href=&quot;#8-note&quot;
class=&quot;skull&quot;&gt;8&lt;/a&gt;. It keeps track of whether a blank line should be added
between the chunks (like
between two class definitions), how much the next line should be indented, and
the expression nesting depth at that point in the code.&lt;/p&gt;

&lt;p&gt;The most important bit of data about the split is the &lt;em&gt;rule&lt;/em&gt; that controls it &lt;a
id=&quot;9&quot; href=&quot;#9-note&quot; class=&quot;skull&quot;&gt;9&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Rules&lt;/h3&gt;

&lt;p&gt;Each potential split in the program is owned by a &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/rule/rule.dart&quot;&gt;rule&lt;/a&gt;. A single rule may
own the splits of several chunks. For example, a series of binary operators of
the same kind like &lt;code&gt;a + b + c + d&lt;/code&gt; uses a single rule for the splits after each
&lt;code&gt;+&lt;/code&gt; operator.&lt;/p&gt;

&lt;p&gt;A rule controls which of its splits break and which don&amp;rsquo;t. It determines this
based on the state that the rule is in, which it calls its &lt;em&gt;value&lt;/em&gt;. You can
think of a rule like a dial and the value is what you&amp;rsquo;ve turned it to. Given a
value, the rule will tell you which of its chunks get split.&lt;/p&gt;

&lt;p&gt;The simplest rule is a &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/rule/rule.dart#L85&quot;&gt;&amp;ldquo;hard split&amp;rdquo; rule&lt;/a&gt;. It says that its chunk
&lt;em&gt;always&lt;/em&gt; splits, so it only has one value: &lt;code&gt;0&lt;/code&gt;. This is useful for things like
line comments where you always need to split after it, even in the middle of an
expression &lt;a id=&quot;10&quot; href=&quot;#10-note&quot; class=&quot;skull&quot;&gt;10&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then there is a &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/rule/rule.dart#L104&quot;&gt;&amp;ldquo;simple&amp;rdquo; split rule&lt;/a&gt;. It allows two values: &lt;code&gt;0&lt;/code&gt; means
none of its chunks split and &lt;code&gt;1&lt;/code&gt; means they all do. Since most splits are
independent of the others, this gets used for most of the splits in the program.&lt;/p&gt;

&lt;p&gt;Beyond that, there are &lt;a href=&quot;https://github.com/dart-lang/dart_style/tree/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/rule&quot;&gt;a handful of special-case rules&lt;/a&gt;. These are used
in places where we want to more precisely control the configuration of a set of
splits. For example, the positional argument list in a function list is
controlled by &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/rule/argument.dart&quot;&gt;a single rule&lt;/a&gt;. A function call like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Will have splits after &lt;code&gt;function(&lt;/code&gt;, &lt;code&gt;first,&lt;/code&gt;, &lt;code&gt;second,&lt;/code&gt;, and &lt;code&gt;third)&lt;/code&gt;. They are
all owned by a single rule that only allows the following configurations:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// 0: Don&amp;#39;t split at all.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 1: Split before the first.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 2: Split before only the last argument.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 3: Split before only the middle argument.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 4: Split before all of them.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having a single rule for this instead of individual rules for each argument lets
us prohibit things like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Constraints&lt;/h3&gt;

&lt;p&gt;Grouping a range of splits under a single rule helps us prevent split
configurations we want to avoid like this, but it&amp;rsquo;s not enough. There are more
complex constraints we want to enforce like: &amp;ldquo;if a split occurs inside a list
element, the list should split too&amp;rdquo;. That avoids output like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fourth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, the list and the &lt;code&gt;+&lt;/code&gt; expression have their own rules, but those rules need
to interact. If the &lt;code&gt;+&lt;/code&gt; takes value &lt;code&gt;1&lt;/code&gt;, the list rule needs to as well. To
support this, rules can &lt;em&gt;constrain&lt;/em&gt; each other. Any rule can limit the values
another rule is allowed to take based on its own value. Typically, this is used
to make a rule inside a nested expression force the rules surrounding itself to
split when it does &lt;a id=&quot;11&quot; href=&quot;#11-note&quot; class=&quot;skull&quot;&gt;11&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, each rule has a &lt;em&gt;cost&lt;/em&gt;. This is a numeric penalty that applies when any
of that rule&amp;rsquo;s chunks are split. This helps us determine which sets of splits
are better or worse than others &lt;a id=&quot;12&quot; href=&quot;#12-note&quot;
class=&quot;skull&quot;&gt;12&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rule costs are only part of how overall fitness is calculated. Most of the cost
calculation comes from &lt;em&gt;spans&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Spans&lt;/h3&gt;

&lt;p&gt;A &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/chunk.dart#L331&quot;&gt;span&lt;/a&gt; marks a series of contiguous chunks that we want to avoid splitting.
I picture it like a rubber band stretching around them. If a split happens in
any of those chunks, the span is broken. When that happens, the solution is
penalized based on the cost of the span.&lt;/p&gt;

&lt;p&gt;Spans can nest arbitrarily deeply. In an expression like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There will be spans around &lt;code&gt;a, b&lt;/code&gt; and &lt;code&gt;c, d&lt;/code&gt; to try to keep those argument lists
from splitting, but also another span around &lt;code&gt;first(a, b), second(c, d)&lt;/code&gt; to keep
the outer argument list from splitting.&lt;/p&gt;

&lt;p&gt;If a split occurs between &lt;code&gt;a,&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, the &lt;code&gt;a, b&lt;/code&gt; span splits, but so does the
&lt;code&gt;first(a, b), second(c, d)&lt;/code&gt; one. However, if a split occurs after &lt;code&gt;first(a, b),&lt;/code&gt;
then the &lt;code&gt;a, b&lt;/code&gt; span is still fine. In this way, spans teach the formatter to
prefer splitting at a higher level of nesting when possible since it breaks
fewer nested spans.&lt;/p&gt;

&lt;h2&gt;Parsing source to chunks&lt;/h2&gt;

&lt;p&gt;Converting your raw source code to this representation is fairly
straightforward. The formatter uses the wonderful &lt;a href=&quot;https://pub.dartlang.org/packages/analyzer&quot;&gt;analyzer&lt;/a&gt; package to parse
your code to an &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;AST&lt;/a&gt;. This gives us a tree structure that represents every
single byte of your program. Unlike many ASTs, it even includes comments.&lt;/p&gt;

&lt;p&gt;Once we have that, the formatter does a &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/source_visitor.dart&quot;&gt;top-down traversal of the
tree&lt;/a&gt;. As it walks, it &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_writer.dart&quot;&gt;writes out chunks, rules, and spans&lt;/a&gt;
for the various grammar productions. This is where the formatting &amp;ldquo;style&amp;rdquo; is
determined.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s no rocket science here, but there are a &lt;em&gt;lot&lt;/em&gt; of &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/chunk_builder.dart#L184&quot;&gt;hairy&lt;/a&gt;
&lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/chunk_builder.dart#L210&quot;&gt;corner&lt;/a&gt; &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/chunk_builder.dart#L283&quot;&gt;cases&lt;/a&gt;. Comments can appear in weird places. We have
to handle weird things like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// comment&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;argument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, we normally would have a split after the first argument owned by an
argument list rule. But the line comment adheres to the &lt;code&gt;,&lt;/code&gt; and has a hard split
after it, so we need to make sure the argument list rule handles that.&lt;/p&gt;

&lt;p&gt;Whitespace is only implicitly tracked by the AST so we have to &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/source_visitor.dart#L1979&quot;&gt;reconstitute
it&lt;/a&gt; in the few places where your original whitespace affects the output.
Having a detailed test suite really helps here.&lt;/p&gt;

&lt;p&gt;Once we&amp;rsquo;ve visited the entire tree, the AST has been converted to a tree of
chunks and a bunch of spans wrapped around pieces of it.&lt;/p&gt;

&lt;h2&gt;Formatting chunks&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve got ourselves a big tree of chunks owned by a slew of rules. Earlier, I
said a rule is like a knob. Now we get to dial them in.&lt;/p&gt;

&lt;p&gt;Doing this naïvely is infeasible. Even a small source file contains hundreds of
individual rules and the set of possible solutions is exponential in the number
of rules.&lt;/p&gt;

&lt;p&gt;The first thing we do is &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/chunk_builder.dart#L736&quot;&gt;divide the chunk list&lt;/a&gt; into regions we &lt;em&gt;know&lt;/em&gt;
can&amp;rsquo;t interfere with each other. These are roughly &amp;ldquo;lines&amp;rdquo; of code. So with:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We know that how we split the first statement has no effect on the second one.
So we run through the list of chunks and break them into shorter lists whenever
we hit a hard split that isn&amp;rsquo;t nested inside an expression.&lt;/p&gt;

&lt;p&gt;Each of these shorter chunk lists is fed to the &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/line_splitter.dart&quot;&gt;line splitter&lt;/a&gt;. Its job is to
pick the best set of values for all the rules used by the chunks in the line. In
most cases, this is trivial: if the whole line fits on the page, every rule gets
set to zero&amp;mdash;no splits&amp;mdash;and we&amp;rsquo;re done.&lt;/p&gt;

&lt;p&gt;When a line doesn&amp;rsquo;t fit, the splitter has to figure out which combination of
rule values produces the best result. That is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The one with the fewest characters that go over the column limit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The one with the lowest cost, based on which rules and spans were split.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Calculating the cost for a set of rule values is pretty easy, but there are
still way too many permutations to brute force it. If we can&amp;rsquo;t brute force it,
how do we do it?&lt;/p&gt;

&lt;h2&gt;How line splitting works&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m a college dropout so my knowledge of algorithms was fairly, um, rudimentary.
So before I interviewed at Google, I spent two days in a hotel room cramming as
many of them&amp;mdash;mostly graph traversal&amp;mdash;in my head as I could. At the
time, I thought graphs would never come up in the interviews&amp;hellip;&lt;/p&gt;

&lt;p&gt;Then I had multiple interview questions that reduced down to doing the right
kind of traversal over a graph. At the time, I thought this stuff would never be
relevant to my actual job&amp;hellip;&lt;/p&gt;

&lt;p&gt;Then I spent the past few years at Google discovering that damn near every
program I have to write can be reduced down to some kind of graph search. I
wrote a &lt;a href=&quot;https://pub.dartlang.org/&quot;&gt;package manager&lt;/a&gt; where dependencies are a transitive closure and
version constraint solving is graph based. My &lt;a href=&quot;https://github.com/munificent/hauberk&quot;&gt;hobby roguelike&lt;/a&gt; uses
graphs for pathfinding. Graphs out the wazoo. I can do BFS in my sleep now.&lt;/p&gt;

&lt;p&gt;Naturally, after several other failed approaches, I found that line splitting
can be handled like a graph search problem &lt;a id=&quot;13&quot; href=&quot;#13-note&quot;
class=&quot;skull&quot;&gt;13&lt;/a&gt;. Each node in the graph represents a
&lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/solve_state.dart&quot;&gt;&lt;em&gt;solution&lt;/em&gt;&lt;/a&gt;&amp;mdash;a set of values for each rule. Solutions can be
&lt;em&gt;partial&lt;/em&gt;: some rules may be left with their values unbound.&lt;/p&gt;

&lt;p&gt;From a given partial solution (including the initial &amp;ldquo;no rules bound&amp;rdquo; one),
there are edge to new partial solutions. Each binds one additional rule to a
value. By starting from an empty solution and walking this graph, we eventually
reach complete solutions where all of the rules have been bound to values.&lt;/p&gt;

&lt;p&gt;Graph search is great if you know where your destination is and you&amp;rsquo;re trying to
find the best path. But we don&amp;rsquo;t actually know that. We don&amp;rsquo;t know what the best
complete solution &lt;em&gt;is&lt;/em&gt;. (If we did, we&amp;rsquo;ve be done already!)&lt;/p&gt;

&lt;p&gt;Given this, no textbook graph search algorithm is sufficient. We need to apply
some domain knowledge&amp;mdash;we need to take advantage of rules and conditions
implicit in the &lt;em&gt;specific&lt;/em&gt; problem we&amp;rsquo;re solving.&lt;/p&gt;

&lt;p&gt;After a dozen dead ends, I found three (sort of four) that are enough to get it
finding the right solution quickly:&lt;/p&gt;

&lt;h3&gt;Bailing early&lt;/h3&gt;

&lt;p&gt;We are trying to minimize two soft constraints at the same time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We want to minimize the number of characters that overflow the line length
limit. We can&amp;rsquo;t make this a hard constraint that there is &lt;em&gt;no&lt;/em&gt; overflow
because it&amp;rsquo;s possible for a long identifier or string literal to overflow in
&lt;em&gt;every&lt;/em&gt; solution. In that case, we still need to find the one that&amp;rsquo;s closest
to fitting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We want to find the lowest cost&amp;mdash;the fewest split rules and broken
spans.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first constraint dominates the second: we&amp;rsquo;ll prefer a solution with any cost
if it fits one more character in. In practice, there is almost always a solution
that does fit, so it usually comes down to picking the lowest cost solution &lt;a
id=&quot;14&quot; href=&quot;#14-note&quot; class=&quot;skull&quot;&gt;14&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We don&amp;rsquo;t know &lt;em&gt;a priori&lt;/em&gt; what the cost of the winning solution will be, but we
do know one useful piece of information: &lt;em&gt;forcing a rule to split always
increases the cost&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If we treat any unbound rule as being implicitly unsplit &lt;a id=&quot;15&quot;
href=&quot;#15-note&quot; class=&quot;skull&quot;&gt;15&lt;/a&gt;, that means the starting solution with
everything unbound always has the lowest cost (zero). We can then explore
outward from there in order of increasing cost by adding one rule at a time.&lt;/p&gt;

&lt;p&gt;This is a basic &lt;a href=&quot;https://en.wikipedia.org/wiki/Best-first_search&quot;&gt;best-first search&lt;/a&gt;: we keep a &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/solve_state_queue.dart&quot;&gt;running queue&lt;/a&gt; of all of
the partial solutions we&amp;rsquo;ve haven&amp;rsquo;t explored yet, sorted from lowest cost to
highest. Each iteration, we pop a solution off.&lt;/p&gt;

&lt;p&gt;If the solution completely fits in the page width, then we know we&amp;rsquo;ve won the
overflow constraint. Since we&amp;rsquo;re exploring in order of increasing cost, we also
know it&amp;rsquo;s the lowest cost. So, ta-da!, &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/line_splitter.dart#L171&quot;&gt;we found the winner and can stop
exploring&lt;/a&gt;. Otherwise, if it has any unbound rules, we enqueue new
solutions, each of which binds one of those to a value.&lt;/p&gt;

&lt;p&gt;We basically explore the entire solution space in order of increasing cost. As
soon as we find a solution that fits in the page, we stop.&lt;/p&gt;

&lt;h3&gt;Avoiding dead ends&lt;/h3&gt;

&lt;p&gt;The above sounds pretty promising, but it turns out that there can be an
imperial ton of &amp;ldquo;low-cost but overflowing&amp;rdquo; solutions. When you&amp;rsquo;re trying to
format a really long line, there are plenty of ways it can &lt;em&gt;not&lt;/em&gt; fit, and this
algorithm will try basically all of them. After all, they&amp;rsquo;re low cost since they
don&amp;rsquo;t have many splits.&lt;/p&gt;

&lt;p&gt;We need to avoid wasting time tweaking rules that aren&amp;rsquo;t part of the problem.
For example, say we&amp;rsquo;re looking at a partial solution like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Blog-friendly 40-char line limit:    |&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;firstCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;secondCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;very long argument string here&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are a bunch of ways we can split the arguments to &lt;code&gt;firstCall()&lt;/code&gt;, but &lt;em&gt;we
don&amp;rsquo;t need to&lt;/em&gt;. Its line already fits. The only line we need to worry about is
the &lt;code&gt;secondCall()&lt;/code&gt; one.&lt;/p&gt;

&lt;p&gt;So, when we are expanding a partial solution, we only bind &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/solve_state.dart#L28&quot;&gt;rules that have
chunks &lt;em&gt;on overflowing lines&lt;/em&gt;&lt;/a&gt;. If all of a rule&amp;rsquo;s chunks are on lines
that already fit, we don&amp;rsquo;t mess with it. In fact, we don&amp;rsquo;t even worry about
rules on any overflowing line but the first. Since tweaking the first line will
affect the others, there&amp;rsquo;s no reason to worry about them yet &lt;a id=&quot;16&quot;
href=&quot;#16-note&quot; class=&quot;skull&quot;&gt;16&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;em&gt;dramatically&lt;/em&gt; cuts down &amp;ldquo;branchiness&amp;rdquo; of the graph. Even though a partial
solution may have dozens of unbound rules, usually only a couple are on long
lines and only those get explored.&lt;/p&gt;

&lt;h3&gt;Pruning redundant branches&lt;/h3&gt;

&lt;p&gt;This gets us pretty far, but the splitter can still go off the deep end in some
cases. The problem is that within large statements, you still run into cases
where how you format part of the statement is &lt;em&gt;mostly&lt;/em&gt; independent of later
parts.&lt;/p&gt;

&lt;p&gt;Take something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Blog-friendly 40-char line limit:    |&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;assertions:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;checked-mode&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;annotations:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;annotations&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;primitives:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;primitives&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;minify:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;minify&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;preserve:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;preserve&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;liveAnalysis:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;live&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;analysis&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;multi:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;multi&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;sourceMap:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;source-map&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each of those named arguments can be split in a few different ways. And, since
those are less nested&amp;mdash;which means fewer split spans&amp;mdash;than that nasty
&lt;code&gt;liveAnalysis:&lt;/code&gt; line, &lt;em&gt;it will try every combination of all of them&lt;/em&gt; before it
finally gets down to the business of splitting that &lt;code&gt;check()&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;The best way to split the &lt;code&gt;liveAnalysis:&lt;/code&gt; line is the best way to split it
regardless of how we split &lt;code&gt;assertions:&lt;/code&gt; or &lt;code&gt;annotations:&lt;/code&gt;. In other words,
there are big branches of the solution space that initially differ in irrelevant
ways, but eventually reconvene to roughly the same solution. We traverse every
single one of them.&lt;/p&gt;

&lt;p&gt;What we need is a way to prune entire branches of the solution space. Given two
partial solutions A and B, if we could say not just &amp;ldquo;A is better than B&amp;rdquo; but
&amp;ldquo;every solution we can get to from A will be better than every solution we can
get to from B&amp;rdquo; then we can discard B &lt;em&gt;and the entire branch of solutions
stemming from it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It took some work, but I finally figured out that you &lt;em&gt;can&lt;/em&gt; do this in many
cases. Given two partial solutions, if one has a lower cost than the other and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They have the same set of unbound rules (but their bound rules have different
values, obviously).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;None of their bound rules are on the same line as an unbound rule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;None of their bound rules place constraints on an unbound rule.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If all of those are true, then the one with a lower cost will always lead to
solutions that also have a lower cost. Its entire branch wins. We can &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/solve_state_queue.dart#L124&quot;&gt;discard
the other solution&lt;/a&gt; and everything that it leads to. Once I got &lt;em&gt;this&lt;/em&gt;
working, the formatter could line split damn near anything in record time &lt;a
id=&quot;17&quot; href=&quot;#17-note&quot; class=&quot;skull&quot;&gt;17&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;An escape hatch&lt;/h3&gt;

&lt;p&gt;Alas, that &amp;ldquo;damn near&amp;rdquo; is significant. There are still a &lt;em&gt;few&lt;/em&gt; cases where the
formatter takes a long time. I&amp;rsquo;ve only ever seen this on machine generated code.
Stuff like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ResolutionCopier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;override&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visitClassDeclaration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ClassDeclaration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ClassDeclaration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_toNode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClassDeclaration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javaBooleanAnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                                    &lt;span class=&quot;n&quot;&gt;_isEqualNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documentationComment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documentationComment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                                    &lt;span class=&quot;n&quot;&gt;_isEqualNodeLists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                                        &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;_isEqualTokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abstractKeyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                    &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abstractKeyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_isEqualTokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classKeyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classKeyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;_isEqualNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_isEqualNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;typeParameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;typeParameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;_isEqualNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extendsClause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extendsClause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;_isEqualNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;withClause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;withClause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_isEqualNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;implementsClause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;implementsClause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;_isEqualTokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;leftBracket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;leftBracket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_isEqualNodeLists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;members&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;members&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_isEqualTokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rightBracket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;toNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rightBracket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yeah, welcome to my waking nightmare. Unsurprisingly, code like this bogs down
the formatter. I want dartfmt to be usable in things like presubmit scripts
where it will have a ton of weird code thrown at it and it &lt;em&gt;must&lt;/em&gt; complete in a
reliable amount of time.&lt;/p&gt;

&lt;p&gt;So there is one final escape hatch. If the line splitter tries, like, 5,000
solutions and still hasn&amp;rsquo;t found a winner yet, it just picks the best it found
so far and &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_splitting/line_splitter.dart#L181&quot;&gt;bails&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In practice, I only see it hit this case on generated code. Thank God.&lt;/p&gt;

&lt;h2&gt;Finally, output&lt;/h2&gt;

&lt;p&gt;Once the line splitter has picked values for all of the rules, the rest is easy.
The formatter &lt;a href=&quot;https://github.com/dart-lang/dart_style/blob/3b3277668b2ff0cb7be954c3217c73264454bd7c/lib/src/line_writer.dart&quot;&gt;walks the tree of chunks&lt;/a&gt;, printing their text. When a
rule forces a chunk to split, it outputs a newline (or two), updates the
indentation appropriately and keeps trucking.&lt;/p&gt;

&lt;p&gt;The end result is a string of (I hope!) beautifully formatted Dart code. So much
work just to add or remove a few spaces!&lt;/p&gt;

&lt;h3&gt;Footnotes&lt;/h3&gt;

&lt;p&gt;&lt;a id=&quot;1-note&quot; href=&quot;#1&quot; class=&quot;skull-note&quot;&gt;1&lt;/a&gt; Yes, I really did brute force
all of the combinations at first. It let me focus on getting the output correct
before I worried about performance. Speed was fine for most statements. The
other few wouldn&amp;rsquo;t finish until after the heat death of the universe.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;2-note&quot; href=&quot;#2&quot; class=&quot;skull-note&quot;&gt;2&lt;/a&gt; For most of the time, the
formatter &lt;em&gt;did&lt;/em&gt; use dynamic programming and memoization. I felt like a wizard
when I first figured out how to do it. It worked fairly well, but was a
nightmare to debug.&lt;/p&gt;

&lt;p&gt;It was &lt;em&gt;highly&lt;/em&gt; recursive, and ensuring that the keys to the memoization table
were precise enough to not cause bugs but not &lt;em&gt;so&lt;/em&gt; precise that the cache
lookups always fail was a very delicate balancing act. Over time, the amount of
data needed to uniquely identify the state of a subproblem grew, including
things like the entire expression nesting stack at a point in the line, and the
memoization table performed worse and worse.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;3-note&quot; href=&quot;#3&quot; class=&quot;skull-note&quot;&gt;3&lt;/a&gt; The IR evolved constantly.
Spans and rules were later additions. Even the way chunks tracked indentation
changed frequently. Indentation used to be stored in levels, where each level
was two spaces. Then directly in spaces. Expression nesting went through a
number of representations.&lt;/p&gt;

&lt;p&gt;In all of this, the IR&amp;rsquo;s job is to balance being easy for the front-end to
&lt;em&gt;produce&lt;/em&gt; while being efficient for the back end to &lt;em&gt;consume&lt;/em&gt;. The back end
really drives this. The IR is structured to be the right data structure for the
algorithm the back end wants to use.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;4-note&quot; href=&quot;#4&quot; class=&quot;skull-note&quot;&gt;4&lt;/a&gt; Comments were the one of the
biggest challenges. The formatter initially assumed there would be no newlines
in some places. Who would expect a newline, say, between the keywords in
&lt;code&gt;abstract class&lt;/code&gt;? Alas, there&amp;rsquo;s nothing preventing a user from doing:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Oh, crap. A line comment.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So I had to do a ton of work to make it resilient in the face of comments and
newlines appearing in all sorts of weird places. There&amp;rsquo;s no single clean
solution for this, just lots of edge cases and special handling.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;5-note&quot; href=&quot;#5&quot; class=&quot;skull-note&quot;&gt;5&lt;/a&gt; The back end is where all of
the performance challenges come from, and it went through two almost complete
rewrites before it ended up where it is today.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;6-note&quot; href=&quot;#6&quot; class=&quot;skull-note&quot;&gt;6&lt;/a&gt; I started from a simpler
formatter written by a teammate that treated text, whitespace, and splits all as
separate chunks. I unified those so that each chunk included non-whitespace
text, line split information, and whitespace information if it didn&amp;rsquo;t split.
That simplified a lot.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;7-note&quot; href=&quot;#7&quot; class=&quot;skull-note&quot;&gt;7&lt;/a&gt; When I added support for
better indentation of nested functions, that broke the code that split source
into separately splittable regions. For a while, a single top-level statement
would be split as a single unit, even if it contained nested functions with
hundreds of lines of code. It was&amp;hellip; not fast.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;8-note&quot; href=&quot;#8&quot; class=&quot;skull-note&quot;&gt;8&lt;/a&gt; Ideally, the split information
in a chunk would describe the split &lt;em&gt;before&lt;/em&gt; the chunk&amp;rsquo;s text. This would avoid
the pointless split information on the last chunk, and also solve annoying
special-case handling of the indentation before the very first chunk.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve tried to correct this mistake a number of times, but it causes a
near-infinite number of off-by-one bugs and I just haven&amp;rsquo;t had the time to push
it all the way through and fix everything.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;9-note&quot; href=&quot;#9&quot; class=&quot;skull-note&quot;&gt;9&lt;/a&gt; Rules are a relatively recent
addition. Originally each chunk&amp;rsquo;s split was handled independently. You could
specify some relations between them like &amp;ldquo;if this chunk splits then this other
one has to as well&amp;rdquo;, but you could not express things like &amp;ldquo;only one of these
three chunks may split&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Eventually, I realized the latter is what I really needed to get argument lists
formatting well, so I conceived of rules as a separate concept and rewrote the
front and line splitter to work using those.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;10-note&quot; href=&quot;#10&quot; class=&quot;skull-note&quot;&gt;10&lt;/a&gt; At first, I thought hard
splits weren&amp;rsquo;t needed. Any place a mandatory newline appears (like between two
statements) is a place where you could just break the list of chunks in two and
line split each half independently. From the line splitter&amp;rsquo;s perspective, there
would be no hard splits.&lt;/p&gt;

&lt;p&gt;Which would work&amp;hellip; except for line comments:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;// with a line comment&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;rightInTheMiddleOfIt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This has to be split as a single unit to get the expression nesting and
indentation correct, but it also contains a mandatory newline after the line
comment.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;11-note&quot; href=&quot;#11&quot; class=&quot;skull-note&quot;&gt;11&lt;/a&gt; There used to be a separate
class for a &amp;ldquo;multisplit&amp;rdquo; to directly handle forcing outer expressions to split
when inner ones did. Once rules came along, they also needed to express
constraints between them, and eventually those constraints were expressive
enough to be able to handle the multisplit behavior directly and multisplits
were removed.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;12-note&quot; href=&quot;#12&quot; class=&quot;skull-note&quot;&gt;12&lt;/a&gt; I spent a &lt;em&gt;lot&lt;/em&gt; of time
tuning costs for different grammar productions to control how tightly bound
different expressions were. The goal was to allow splits at the places where the
reader thought code was &amp;ldquo;loosest&amp;rdquo;, so stuff like higher precedence expressions
would have higher costs.&lt;/p&gt;

&lt;p&gt;Tuning these costs was a nightmare. It was like a hanging mobile where tweaking
one cost would unbalance all of the others. On more than one occasion, I found
myself considering making them floating point instead of integers, a sure sign
of madness.&lt;/p&gt;

&lt;p&gt;It turns out spans are what you really want in order to express looseness.
Nested infix operators then fall out naturally because you have more spans
around the deeper nested operands. The parse tree gives it to you for free.&lt;/p&gt;

&lt;p&gt;These days, almost every chunk and span has a cost of 1, and it&amp;rsquo;s the &lt;em&gt;quantity&lt;/em&gt;
of nested spans and contained chunks that determine where it splits.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;13-note&quot; href=&quot;#13&quot; class=&quot;skull-note&quot;&gt;13&lt;/a&gt; I had known that
&lt;a href=&quot;http://clang.llvm.org/docs/ClangFormat.html&quot;&gt;clang-format&lt;/a&gt; worked this way for a long time, but I could never wrap my head
around how to apply it to dartfmt&amp;rsquo;s richer chunk/rule/span system.&lt;/p&gt;

&lt;p&gt;I took a lot of walks along the bike trail next to work trying to think through
a way to get graph search working when the two numbers being optimized (overflow
characters and cost) are in direct opposition, and we don&amp;rsquo;t even know what the
goal state looks like. It took a long time before it clicked. Even then, it
didn&amp;rsquo;t work at all until I figured out the right heuristics to use to optimize
it.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;14-note&quot; href=&quot;#14&quot; class=&quot;skull-note&quot;&gt;14&lt;/a&gt; For a long time, overflow
and cost were treated as a single fitness function. Every overflow character
just added a very high value to the cost to make the splitter strongly want to
avoid them.&lt;/p&gt;

&lt;p&gt;Splitting overflow out as a separate metric turned out to be key to getting the
graph search to work because it let us order the solutions by cost independently
of overflow characters.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;15-note&quot; href=&quot;#15&quot; class=&quot;skull-note&quot;&gt;15&lt;/a&gt; I went back and forth on
how an unbound rule should implicitly behave. Treating it as implicitly split
gives you solutions with fewer overflow characters sooner. Treating it as
unsplit gives you lower costs.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;16-note&quot; href=&quot;#16&quot; class=&quot;skull-note&quot;&gt;16&lt;/a&gt; Oh, God. I tried a million
different ways to reduce the branchiness before I hit on only looking at rules
in the first long line. I&amp;rsquo;m still amazed that it works.&lt;/p&gt;

&lt;p&gt;I could also talk about how controlling branchiness lets us avoid reaching the
same state from multiple different paths. After all, it&amp;rsquo;s a &lt;em&gt;graph&lt;/em&gt;, but
everything I&amp;rsquo;ve described talks about it like it&amp;rsquo;s a tree. By carefully
controlling how we extend partial solutions, we ensure we only take a single
path to any given complete solution.&lt;/p&gt;

&lt;p&gt;Before I got that working, I had to keep a &amp;ldquo;visited&amp;rdquo; set to make sure we didn&amp;rsquo;t
explore the same regions twice, but just maintaining that set was a big
performance sink.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;17-note&quot; href=&quot;#17&quot; class=&quot;skull-note&quot;&gt;17&lt;/a&gt; Discarding overlapping
branches is the last macro-optimization I did and its behavior is very subtle.
Correctly detecting when two partial solutions overlap took a &lt;em&gt;lot&lt;/em&gt; of
iteration. Every time I thought I had it, one random weird test would fail where
it accidentally collapsed two branches that &lt;em&gt;would&lt;/em&gt; eventually diverge.&lt;/p&gt;

&lt;p&gt;That bullet list was paid for in blood, sweat, and tears. I honestly don&amp;rsquo;t think
I could have figured them out at all until late in the project when I had a
&lt;a href=&quot;https://github.com/dart-lang/dart_style/tree/3b3277668b2ff0cb7be954c3217c73264454bd7c/test&quot;&gt;comprehensive test suite&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2015/09/07/what-the-hero-sees</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2015/09/07/what-the-hero-sees"/>
    <title>What the Hero Sees: Field-of-View for Roguelikes</title>
    <published>2015-09-07T00:00:00-07:00</published>
    <updated>2015-09-07T00:00:00-07:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;style&gt;
canvas {
  display: inline-block;
  max-width: 100%;
  cursor: crosshair;
}
&lt;/style&gt;

&lt;p&gt;This is a record for me. I&amp;rsquo;ve been procrastinating this post for eight years. I
moved four times, got married, had two kids, and ported my roguelike to &lt;a href=&quot;https://www.dartlang.org/&quot;&gt;a
language&lt;/a&gt; that didn&amp;rsquo;t exist when I first wrote the code this post is
about. You can thank Simon Andersson for prodding me to finally write it down.&lt;/p&gt;

&lt;p&gt;Every good game, or genre of games, has a pyramid of rewards. From simple
pleasures that mete out a droplet of endorphins when you click the next button
up to the deep, abiding feeling of accomplishment you get from slaying the final
boss on nightmare mode.&lt;/p&gt;

&lt;p&gt;The roguelike genre standardizes many of these, and one of my favorites is the
joy of &lt;em&gt;exploring the dungeon&lt;/em&gt;. You start out on a black screen, only one tiny
room visible. As you walk around, the map incrementally fills in&amp;mdash;a perfect
graphical representation of your own knowledge and mastery increasing.&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;explore&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Click and drag the hero to explore. Click walls and floors to
  alter the dungeon.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There wouldn&amp;rsquo;t be much to explore if your hero could see through walls. The
second they entered the dungeon, the entire map would be filled in, all of the
crypt&amp;rsquo;s hidden secrets laid bare to warrior and player alike. To prevent that,
we need to simulate something that seems trivial: &lt;em&gt;walls blocking the hero&amp;rsquo;s
view&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the roguelike scene, this is referred to as &lt;em&gt;field of view&lt;/em&gt;, and there are &lt;a href=&quot;http://www.roguebasin.com/index.php?title=Field_of_Vision&quot;&gt;a
number of ways to do it&lt;/a&gt;. Many of the posts linked there talk about &amp;ldquo;light&amp;rdquo;
and &amp;ldquo;shadow&amp;rdquo; as well, but they calculate the same thing as visilibity. In both
cases, we&amp;rsquo;re trying to find the set of tiles that can be reached by rays
emanating from some point source. I&amp;rsquo;ll use both terms interchangeably.&lt;/p&gt;

&lt;h2&gt;Brute force line-of-sight?&lt;/h2&gt;

&lt;p&gt;The simplest solution is to repurpose your line-of-sight code. You already need
code to determine if there is an open line from one point to another on the map.
You use that to tell if things like arrows and fireballs reach their target or
bounce harmlessly off the dungeon wall.&lt;/p&gt;

&lt;p&gt;This is invariably done using &lt;a href=&quot;https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm&quot;&gt;Bresenham&amp;rsquo;s line algorithm&lt;/a&gt;. It&amp;rsquo;s one
of the true classics of graphics programming&amp;mdash;an elegant, simple algorithm
from 1962 that&amp;rsquo;s still useful today. (This kind of living connection to CS&amp;rsquo;s
past is one of the things I love about hacking on a roguelike. How often do you
have a good reason to recode a procedure originally devised for a 1950s-era drum
plotter?)&lt;/p&gt;

&lt;p&gt;As you&amp;rsquo;d imagine for an algorithm designed to run on a machine that took punch
cards, it&amp;rsquo;s very efficient&amp;hellip; for tracing a line between &lt;em&gt;two points&lt;/em&gt;. But field
of view is different: we need to scan the entire dungeon&amp;mdash;or at least the
part that fits on the player&amp;rsquo;s screen&amp;mdash;and calculate the visibility of
&lt;em&gt;every&lt;/em&gt; tile.&lt;/p&gt;

&lt;p&gt;You actually &lt;em&gt;can&lt;/em&gt; run Bresenham a few thousand times whenever the hero moves on
a modern machine, but doing that feels, well, like cheating somehow. Can we come
up with something more efficient?&lt;/p&gt;

&lt;p&gt;The answer is, of course, &amp;ldquo;yes&amp;rdquo;. (It would be a short post if it wasn&amp;rsquo;t.) And,
in fact, a lot of others have already done so. But, one lazy sunny Saturday
morning in 2006, I didn&amp;rsquo;t see any I liked and wanted to come up with one that
made more sense to me.&lt;/p&gt;

&lt;h2&gt;Pieces of eight&lt;/h2&gt;

&lt;p&gt;If you have the mind of a programmer, the first thing you do when presented with
a problem is to break it into multiple (hopefully) smaller problems. Our goal is
to calculate the entire field of view surrounding the hero, but we can slice
that 360&amp;deg; problem into 45&amp;deg; pie pieces. One looks like this:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;octant&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Click to paint a wedge.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This wedge is called an &lt;a href=&quot;https://en.wikipedia.org/wiki/Octant_(plane_geometry)&quot;&gt;&lt;em&gt;octant&lt;/em&gt;&lt;/a&gt;, and it&amp;rsquo;s common in 2D algorithms. We
can paint every tile in that triangle like so:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxDistance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;paint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we take that wedge and apply some transformations, we can cover the entire
field around the hero. The above code is most of the way there. If you squint,
you can see there are two coordinate systems. The &lt;code&gt;row&lt;/code&gt; and &lt;code&gt;col&lt;/code&gt; variables are
in the octant&amp;rsquo;s coordinate space. Meanwhile, &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are in real tile
space&amp;mdash;what you see on screen.&lt;/p&gt;

&lt;p&gt;The first two lines inside the loops map octant space to tile space. Using just
&lt;code&gt;+&lt;/code&gt; and &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;row&lt;/code&gt; and &lt;code&gt;col&lt;/code&gt;, there are eight ways to calculate &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;.
Each represents a reflection or 90&amp;deg; rotation of the original octant. If we
enumerate them all, we get:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformOctant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each case represents a different octant, starting at the top and going clockwise
around the circle. Painting them all covers the whole view (with a bit of
innocuous overlap):&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;octants&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Click to paint the whole view.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;From here on out, we only have deal with a single triangle&amp;rsquo;s worth of &lt;code&gt;row&lt;/code&gt; and
&lt;code&gt;col&lt;/code&gt;, and we can cover the entire field of view just by running the same code
eight times, once for each octant.&lt;/p&gt;

&lt;h2&gt;A Line of Shadows&lt;/h2&gt;

&lt;p&gt;Another way to approach a problem is to negate it, and that&amp;rsquo;s what this
algorithm does. Instead of calculating which tiles are visible, it figures out
which are hidden, which put it in a family of algorithms that do &amp;ldquo;shadow
casting&amp;rdquo;. Before I explain it, try it out yourself:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;shadow-cast&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Drag the slider up to advance the shadow line. Click anywhere
  else to change the dungeon.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;We start at the hero and work upwards one row at a time. As we sweep through the
octant, we incrementally update a data structure called the &lt;em&gt;shadow line&lt;/em&gt;. It&amp;rsquo;s
the white line you see next to the slider. It tracks which parts of the row are
in the shade of opaque tiles on previous rows and which aren&amp;rsquo;t.&lt;/p&gt;

&lt;p&gt;The line is a series of segments, each representing one obscured region of the
line. We can define this like so:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShadowLine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Shadow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The interesting question is, &amp;ldquo;What is the &lt;em&gt;range&lt;/em&gt; of &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt;?&amp;rdquo; The
naïve answer is to use tile coordinates. If we&amp;rsquo;re five rows in and the shadow
line is five tiles long, the segment coordinates would range from 0 to 5.&lt;/p&gt;

&lt;p&gt;The problem is that since light expands outwards from a point, the shadows
stretch out as they get farther away. We don&amp;rsquo;t want to have to recalculate the
segment positions each time we advance a row and the rays spread out.&lt;/p&gt;

&lt;p&gt;Instead, we store their &lt;em&gt;slopes&lt;/em&gt;. Regardless of what row we&amp;rsquo;re on, they always
range from 0 (the short edge of the octant) to 1 (the diagonal edge). They are
distance-independent. This is what the black line in the demo above shows. As
you click to add and remove wall, you can see new shadows appear, but they don&amp;rsquo;t
move or grow as you sweep the row up and down.&lt;/p&gt;

&lt;h2&gt;Projecting a tile&lt;/h2&gt;

&lt;p&gt;The tricky part is calculating those slopes given some tile in the octant. There
are a couple of corner cases to consider. Literally. A tile is a square, and the
shadow it projects goes from one corner of the square to another.&lt;/p&gt;

&lt;p&gt;Given our canonical octant, we know the tile will be above and to the right of
the hero. That means the projected shadow&amp;rsquo;s extent will always be from the
top-left corner of a tile to the bottom-right corner. The other two corners lie
in the middle of the shadow. (This isn&amp;rsquo;t strictly true if the tile is straight
up from the hero, but we can safely ignore that.)&lt;/p&gt;

&lt;p&gt;What we need, then, is to calculate the slopes of those two corners of a tile.
The math is a kind of fussy, but it&amp;rsquo;s:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;/// Creates a [Shadow] that corresponds to the projected&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// silhouette of the tile at [row], [col].&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projectTile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topLeft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bottomRight&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;topLeft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bottomRight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function has two uses. The obvious one is that we call this for each opaque
tile and add its result to the shadow line. But the projection comes into play
before that too.&lt;/p&gt;

&lt;p&gt;You can think of the result of this function as the shadow that the tile casts
&lt;em&gt;past&lt;/em&gt; itself, but it also describes the projection from the hero &lt;em&gt;to&lt;/em&gt; this
tile. In other words, it describes which angles need to be unblocked for this
tile to be visible.&lt;/p&gt;

&lt;p&gt;When we scan a row, we call &lt;code&gt;projectTile()&lt;/code&gt; on every tile&amp;mdash;transparent or
opaque&amp;mdash; and compare it to the existing shadow line. If the tile&amp;rsquo;s
projection is covered by the shadow line, we know it can&amp;rsquo;t be seen. If it isn&amp;rsquo;t,
it can.&lt;/p&gt;

&lt;p&gt;An interesting edge case is tiles whose projection is &lt;em&gt;partially&lt;/em&gt; covered by the
shadow line. Different games take different approaches here. Mine is considered
&lt;em&gt;permissive&lt;/em&gt;: if you can see any part of a tile, it&amp;rsquo;s visible. A tile&amp;rsquo;s
projection has to be totally covered by the shadow to be hidden. If you want
something less permissive, this algorithm is easy to tweak.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s code! First, we&amp;rsquo;ll add a method to see if one shadow totally covers
another:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Shadow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;/// Returns `true` if [other] is completely covered by this shadow.&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we use that to see if any shadow in the line covers the tile:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShadowLine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isInShadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using that, we can determine the visibility of every tile in a row. Given a
ShadowLine in &lt;code&gt;line&lt;/code&gt;, and a set of tiles in &lt;code&gt;tiles&lt;/code&gt;, it&amp;rsquo;s:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_projectTile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformOctant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isVisible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isInShadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Inky pools of shadows&lt;/h2&gt;

&lt;p&gt;We can calculate which tiles are obscured by the shadow line, but that isn&amp;rsquo;t
very useful since our shadow line is always empty right now. Let&amp;rsquo;s fix that.&lt;/p&gt;

&lt;p&gt;As we trace the row, each time we hit an opaque tile, we add it to the shadow
line. If the shadow line was a simple list of these little shadow segments, the
list would get longer and longer. In a dense dungeon, the hero may be near
hundreds of solid tiles. Having to walk through an increasingly long list of
shadow segments to see if a tile is obscured would get slower and slower.&lt;/p&gt;

&lt;p&gt;Fortunately, I have a simple fix that makes the algorithm get &lt;em&gt;faster&lt;/em&gt; as tiles
occlude more of the view. &lt;em&gt;This&lt;/em&gt; is the part where I think my algorithm is
pretty cool, and it&amp;rsquo;s why I&amp;rsquo;m excited to share it with you.&lt;/p&gt;

&lt;p&gt;Often, when a new segment is added to the shadow line, it overlaps other
shadows. When that happens, we &lt;em&gt;merge&lt;/em&gt; it with the existing shadows. The end
result is that the shadow line will have a single &lt;code&gt;Shadow&lt;/code&gt; object for each
&lt;em&gt;contiguous&lt;/em&gt; range of obscured area.&lt;/p&gt;

&lt;p&gt;This does mean adding a new shadow to the line is more complex. There are a
handful of cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The shadow is contained within an existing one.&lt;/strong&gt; That means the new shadow
doesn&amp;rsquo;t cover any new territory, so we can discard it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The shadow doesn&amp;rsquo;t overlap any other ones.&lt;/strong&gt; In this case, we insert it in
sorted order between the segments that come before and after it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The shadow overlaps another shadow on its starting edge.&lt;/strong&gt; We take the
previous shadow and grow it to encompass the new shadow&amp;rsquo;s endpoint and
discard the new one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The shadow overlaps another shadow on its ending edge.&lt;/strong&gt; Do the same thing,
but in reverse: grow the following shadow to cover the new one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The shadow overlaps shadows on &lt;em&gt;both&lt;/em&gt; ends.&lt;/strong&gt; This is the fun one. We take
the previous shadow and extend it to cover the &lt;em&gt;next&lt;/em&gt; shadow&amp;rsquo;s endpoint. Then
we discard both the new shadow and that next one.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first case doesn&amp;rsquo;t change the list of shadows at all. In the second case,
the list of shadows gets longer. In the next two, adding a new shadow doesn&amp;rsquo;t
grow the list, it just shifts an endpoint. The last case is the fun one: there,
the list gets &lt;em&gt;shorter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;(Pop quiz! Why don&amp;rsquo;t we have to worry about cases where a shadow overlaps more
than two existing ones?)&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the entire method to add a shadow to the line:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShadowLine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Shadow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Figure out where to slot the new shadow in the list.&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Stop when we hit the insertion point.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// The new shadow is going here. See if it overlaps the&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// previous or next.&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;overlappingPrevious&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;overlappingPrevious&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;overlappingNext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;overlappingNext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Insert and unify with overlapping shadows.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;overlappingNext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;overlappingPrevious&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Overlaps both, so unify one and delete the other.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;overlappingPrevious&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;overlappingNext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;removeAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Overlaps the next one, so unify it with that.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;overlappingNext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;overlappingPrevious&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Overlaps the previous one, so unify it with that.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;overlappingPrevious&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Does not overlap anything, so insert.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;OK, so that&amp;rsquo;s kind of hairy, but it&amp;rsquo;s not deep magic, just a bunch of different
cases to handle. Clever readers are probably wondering why we don&amp;rsquo;t do a binary
search to find the insertion point. The list is sorted after all. If you want to
be super smart, go for it. In practice, I don&amp;rsquo;t think it makes much of a
difference. The maximum size of the list is small enough that a linear search
may actually be faster.&lt;/p&gt;

&lt;p&gt;(Pop quiz two! What &lt;em&gt;is&lt;/em&gt; the maximum size of the list? Show your work.)&lt;/p&gt;

&lt;p&gt;Very clever readers may have noticed we don&amp;rsquo;t check for the first case, a
completely contained shadow here. That&amp;rsquo;s because we&amp;rsquo;ve already done that check.
Earlier, when we detect if this tile is visible, that also tells us if it&amp;rsquo;s
shadow is contained. If it is, we don&amp;rsquo;t bother calling &lt;code&gt;add()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s another simple optimization we can do. If we get to the point where the
shadow line is a single segment from 0 to 1&amp;mdash;in other words, the whole line
is in shadow&amp;mdash;then we can skip all of the projection calculation, updating,
etc. Every tile will be hidden after that. Here&amp;rsquo;s how we detect that:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShadowLine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isFullShadow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_shadows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;OK, so we have code to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Walk over every octant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Walk every tile in an octant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update the tile&amp;rsquo;s visibility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update the shadow line if the tile is opaque.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let&amp;rsquo;s stitch the last few pieces together along with a dash of bounds checking.
Building on top of what we have above, here&amp;rsquo;s the top-level code to update the
visibility of the whole dungeon:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;refreshVisibility&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;refreshOctant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;refreshOctant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ShadowLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fullShadow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Stop once we go out of bounds.&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformOctant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformOctant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// If we&amp;#39;ve traversed out of bounds, bail on this row.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fullShadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isVisible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projectTile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Set the visibility of this tile.&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isInShadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isVisible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Add any opaque tiles to the shadow map.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isWall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;fullShadow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isFullShadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there we have it. It runs very fast in wide open areas since there will be
few shadow segments and the list is short. Likewise, it runs fast in closed
areas since the shadow list will also be short&amp;mdash;it will contain a small
number of long segments. It performs the worst in &amp;ldquo;spotty&amp;rdquo; areas with lots of
small trees or pillars, but even there, the performance is pretty solid.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d love to say I implemented a bunch of other algorithms and this one came out
the winner, but honestly I was too lazy to that. I will say that this has never
showed up as a hot spot when I&amp;rsquo;ve profiled the game. That&amp;rsquo;s good enough for me,
and I hope this will be helpful for you too.&lt;/p&gt;

&lt;p&gt;If you want to see all of the code for these demos, it&amp;rsquo;s &lt;a href=&quot;https://github.com/munificent/fov&quot;&gt;here&lt;/a&gt;. Or, in
the context of &lt;a href=&quot;https://github.com/munificent/hauberk&quot;&gt;my game&lt;/a&gt; &lt;a href=&quot;https://github.com/munificent/hauberk/blob/master/lib/src/engine/fov.dart&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;script type=&quot;application/dart&quot; src=&quot;/code/2015-09-07-what-the-hero-sees/main.dart&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/code/2015-09-07-what-the-hero-sees/packages/browser/dart.js&quot;&gt;&lt;/script&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function"/>
    <title>What Color is Your Function?</title>
    <published>2015-02-01T00:00:00-08:00</published>
    <updated>2015-02-01T00:00:00-08:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;p&gt;I don&amp;rsquo;t know about you, but nothing gets me going in the morning quite like a
good old fashioned programming language rant. It stirs the blood to see someone
skewer one of those &lt;a href=&quot;http://www.paulgraham.com/avg.html&quot;&gt;&amp;ldquo;blub&amp;rdquo;&lt;/a&gt; languages the plebians use, muddling through
their day with it between furtive visits to StackOverflow.&lt;/p&gt;

&lt;p&gt;(Meanwhile, you and I, only use the most enlightened of languages. Chisel-sharp
tools designed for the manicured hands of expert craftspersons such as
ourselves.)&lt;/p&gt;

&lt;p&gt;Of course, as the &lt;em&gt;author&lt;/em&gt; of said screed, I run a risk. The language I mock
could be one you like! Without realizing it, I could have let the rabble into
my blog, pitchforks and torches at the ready, and my fool-hardy pamphlet could
draw their ire!&lt;/p&gt;

&lt;p&gt;To protect myself from the heat of those flames, and to avoid offending your
possibly delicate sensibilities, instead, I&amp;rsquo;ll rant about a language I just
made up. A strawman whose sole purpose is to be set aflame.&lt;/p&gt;

&lt;p&gt;I know, this seems pointless right? Trust me, by the end, we&amp;rsquo;ll see whose face
(or faces!) have been painted on his straw noggin.&lt;/p&gt;

&lt;h2&gt;A new language&lt;/h2&gt;

&lt;p&gt;Learning an entire new (crappy) language just for a blog post is a tall order,
so let&amp;rsquo;s say it&amp;rsquo;s mostly similar to one you and I already know. We&amp;rsquo;ll say it
has syntax sorta like JS. Curly braces and semicolons. &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, etc. The
&lt;em&gt;lingua franca&lt;/em&gt; of the programming grotto.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m picking JS &lt;em&gt;not&lt;/em&gt; because that&amp;rsquo;s what this post is about. It&amp;rsquo;s just that
it&amp;rsquo;s the language you, statistical representation of the average reader, are
most likely to be able grok. Voilà:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thisIsAFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;It&amp;#39;s awesome&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because our strawman is a &lt;em&gt;modern&lt;/em&gt; (shitty) language, we also have first-class
functions. So you can make something like like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// Return a list containing all of the elements in collection&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// that match predicate.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;predicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;predicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is one of those &lt;em&gt;higher-order&lt;/em&gt; functions, and, like the name implies, they
are classy as all get out and super useful. You&amp;rsquo;re probably used to them for
mucking around with collections, but once you internalize the concept, you
start using them damn near everywhere.&lt;/p&gt;

&lt;p&gt;Maybe in your testing framework:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;An apple&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ain&amp;#39;t no orange&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Apple&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Orange&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or when you need to parse some data:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;LEFT_BRACKET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Parse a list literal...&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;consume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RIGHT_BRACKET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So you go to town and write all sorts of awesome reusable libraries and
applications passing around functions, calling functions, returning functions.
Functapalooza.&lt;/p&gt;

&lt;h2&gt;What color is your function?&lt;/h2&gt;

&lt;p&gt;Except wait. Here&amp;rsquo;s where our language gets screwy. It has this one peculiar
feature:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Every function has a color.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each function&amp;mdash;anonymous callback or regular named one&amp;mdash;is either red
or blue. Since my blog&amp;rsquo;s code highlighter can&amp;rsquo;t handle actual color, we&amp;rsquo;ll say
the syntax is like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingAzure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This is a blue function...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingCarnelian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This is a red function...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are &lt;em&gt;no&lt;/em&gt; colorless functions in the language. Want to make a function?
Gotta pick a color. Them&amp;rsquo;s the rules. And, actually, there are a couple more
rules you have to follow too:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The way you call a function depends on its color.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine a &amp;ldquo;blue call&amp;rdquo; syntax and a &amp;ldquo;red call&amp;rdquo; syntax. Something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doSomethingAzure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...)&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;doSomethingCarnelian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When calling a function, you need to use the call that corresponds to its color.
If you get it wrong&amp;mdash;call a red function with &lt;code&gt;•blue&lt;/code&gt; after the parentheses
or vice versa&amp;mdash;it does something bad. Dredge up some long-forgotten
nightmare from your childhood like a clown with snakes for arms hiding under
your bed. That jumps out of your monitor and sucks out your vitreous humour.&lt;/p&gt;

&lt;p&gt;Annoying rule, right? Oh, and one more:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. You can only call a red function from within another red function.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; call a blue function from with a red one. This is kosher:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingCarnelian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;doSomethingAzure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But you can&amp;rsquo;t go the other way. If you try to do this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingAzure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;doSomethingCarnelian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;•&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, you&amp;rsquo;re gonna get a visit from old Spidermouth the Night Clown.&lt;/p&gt;

&lt;p&gt;This makes writing higher-order functions like our &lt;code&gt;filter()&lt;/code&gt; example trickier.
We have to pick a color for &lt;em&gt;it&lt;/em&gt; and that affects the colors of the functions
we&amp;rsquo;re allowed to pass to it. The obvious solution is to make &lt;code&gt;filter()&lt;/code&gt; red.
That way, it can take either red or blue functions and call them. But then we
run into the next itchy spot in the hairshirt that is this language:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Red functions are more painful to call.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For now, I won&amp;rsquo;t precisely define &amp;ldquo;painful&amp;rdquo;, but just imagine that the
programmer has to jump through some kind of annoying hoops every time they call
a red function. Maybe it&amp;rsquo;s really verbose, or maybe you can&amp;rsquo;t do it inside
certain kinds of statements. Maybe you can only call them on line numbers that
are prime.&lt;/p&gt;

&lt;p&gt;What matters is that, if you decide to make a function red, everyone using your
API will want to spit in your coffee and/or deposit some even less savory
fluids in it.&lt;/p&gt;

&lt;p&gt;The obvious solution then is to &lt;em&gt;never&lt;/em&gt; use red functions. Just make everything
blue and you&amp;rsquo;re back to the sane world where all functions have the same color,
which is equivalent to them all having no color, which is equivalent to our
language not being entirely stupid.&lt;/p&gt;

&lt;p&gt;Alas, the sadistic language designers&amp;mdash;and we all know all programming
language designers are sadists, don&amp;rsquo;t we?&amp;mdash;jabbed one final thorn in our
side:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Some core library functions are red.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are some functions built in to the platform, functions that we &lt;em&gt;need&lt;/em&gt; to
use, that we are unable to write ourselves, that only come in red. At this
point, a reasonable person might think the language hates us.&lt;/p&gt;

&lt;h2&gt;It&amp;rsquo;s functional programming&amp;rsquo;s fault!&lt;/h2&gt;

&lt;p&gt;You might be thinking that the problem here is we&amp;rsquo;re trying to use higher-order
functions. If we just stop flouncing around in all of that functional frippery
and write normal blue collar first-order functions like God intended, we&amp;rsquo;d
spare ourselves all the heartache.&lt;/p&gt;

&lt;p&gt;If we only call blue functions, make our function blue. Otherwise, make it red.
As long as we never make functions that accept functions, we don&amp;rsquo;t have to
worry about trying to be &amp;ldquo;polymorphic over function color&amp;rdquo; (polychromatic?) or
any nonsense like that.&lt;/p&gt;

&lt;p&gt;But, alas, higher order functions are just one example. This problem is
pervasive any time we want to break our program down into separate functions
that get reused.&lt;/p&gt;

&lt;p&gt;For example, let&amp;rsquo;s say we have a nice little blob of code that, I don&amp;rsquo;t know,
implements Dijkstra&amp;rsquo;s algorithm over a graph representing how much your social
network are crushing on each other. (I spent way too long trying to decide what
such a result would even represent. Transitive undesirability?)&lt;/p&gt;

&lt;p&gt;Later, you end up needing to use this same blob of code somewhere else. You do
the natural thing and hoist it out into a separate function. You call it from
the old place and your new code that uses it. But what color should it be?
Obviously, you&amp;rsquo;ll make it blue if you can, but what if it uses one of those
nasty red-only core library functions?&lt;/p&gt;

&lt;p&gt;What if the new place you want to call it is blue? You&amp;rsquo;ll have to turn it red.
Then you&amp;rsquo;ll have to turn the function that calls &lt;em&gt;it&lt;/em&gt; red. Ugh. No matter what,
you&amp;rsquo;ll have to think about color constantly. It will be the sand in your
swimsuit on the beach vacation of development.&lt;/p&gt;

&lt;h2&gt;A colorful allegory&lt;/h2&gt;

&lt;p&gt;Of course, I&amp;rsquo;m not really talking about color here, am I? It&amp;rsquo;s an allegory, a
literary trick. The Sneetches isn&amp;rsquo;t about stars on bellies, it&amp;rsquo;s about race. By
now, you may have an inkling of what color actually represents. If not, here&amp;rsquo;s
the big reveal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Red functions are asynchronous ones.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re programming in JavaScript on Node.js, everytime you define a function
that &amp;ldquo;returns&amp;rdquo; a value by invoking a callback, you just made a red function.
Look back at that list of rules and see how my metaphor stacks up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Synchronous functions return values, async ones do not and instead invoke
callbacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Synchronous functions give their result as a return value, async functions
give it by invoking a callback you pass to it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can&amp;rsquo;t call an async function from a synchronous one because you won&amp;rsquo;t be
able to determine the result until the async one completes later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Async functions don&amp;rsquo;t compose in expressions because of the callbacks, have
different error-handling, and can&amp;rsquo;t be used with &lt;code&gt;try/catch&lt;/code&gt; or inside a lot
of other control flow statements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node&amp;rsquo;s whole shtick is that the core libs are all asynchronous. (Though they
did dial that back and start adding &lt;code&gt;___Sync()&lt;/code&gt; versions of a lot of
things.)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When people talk about &amp;ldquo;callback hell&amp;rdquo; they&amp;rsquo;re talking about how annoying it is
to have red functions in their language. When they create &lt;a href=&quot;https://www.npmjs.com/search?q=async&quot;&gt;4089 libraries for
doing asynchronous programming&lt;/a&gt;, they&amp;rsquo;re trying to cope at the library
level with a problem that the language foisted onto them.&lt;/p&gt;

&lt;h2&gt;I promise the future is better&lt;/h2&gt;

&lt;p&gt;People in the Node community have realized that callbacks are a pain for a long
time, and have looked around for solutions. One technique that gets a bunch of
people excited is &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;em&gt;promises&lt;/em&gt;&lt;/a&gt;, which you may also know by their
rapper name &amp;ldquo;futures&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;These are sort of a jacked up wrapper around a callback and an error handler.
If you think of passing a callback and errorback to a function as a &lt;em&gt;concept&lt;/em&gt;,
a promise is basically a &lt;em&gt;reification&lt;/em&gt; of that idea. It&amp;rsquo;s a first-class object
that represents an asynchronous operation.&lt;/p&gt;

&lt;p&gt;I just jammed a bunch of fancy PL language in that paragraph so it probably
sounds like a sweet deal, but it&amp;rsquo;s basically snake oil. Promises &lt;em&gt;do&lt;/em&gt; make
async code a little easier to write. They compose a bit better, so rule #4
isn&amp;rsquo;t &lt;em&gt;quite&lt;/em&gt; so onerous.&lt;/p&gt;

&lt;p&gt;But, honestly, it&amp;rsquo;s like the difference between being punched in the gut versus
punched in the privates. Less painful, yes, but I don&amp;rsquo;t think anyone should
really get thrilled about the value proposition.&lt;/p&gt;

&lt;p&gt;You still can&amp;rsquo;t use them with exception handling or other control flow
statements. You still can&amp;rsquo;t call a function that returns a future from
synchronous code. (Well, you &lt;em&gt;can&lt;/em&gt;, but if you do, the person who later
maintains your code will invent a time machine, travel back in time to the
moment that you did this and stab you in the face with a #2 pencil.)&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ve still divided your entire world into asynchronous and synchronous halves
and all of the misery that entails. So, even if your language features promises
or futures, its face looks an awful lot like the one on my strawman.&lt;/p&gt;

&lt;p&gt;(Yes, that means even &lt;a href=&quot;http://dartlang.org&quot;&gt;Dart&lt;/a&gt;, the language I work on. That&amp;rsquo;s why I&amp;rsquo;m so
excited some of the team are &lt;a href=&quot;https://github.com/dart-lang/fletch&quot;&gt;experimenting with other concurrency
models&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;I&amp;rsquo;m awaiting a solution&lt;/h2&gt;

&lt;p&gt;C# programmers are probably feeling pretty smug right now (a condition they&amp;rsquo;ve
increasingly fallen prey to as Hejlsberg and company have piled sweet feature
after sweet feature into the language). In C#, you can use &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/hh191443.aspx&quot;&gt;the &lt;code&gt;await&lt;/code&gt;
keyword&lt;/a&gt; to invoke an
asynchronous function.&lt;/p&gt;

&lt;p&gt;This lets you make asynchronous calls just as easily as you can synchronous
ones, with the tiny addition of a cute little keyword. You can nest &lt;code&gt;await&lt;/code&gt;
calls in expressions, use them in exception handling code, stuff them inside
control flow. Go nuts. Make it rain &lt;code&gt;await&lt;/code&gt; calls like a they&amp;rsquo;re dollars in the
advance you got for your new rap album.&lt;/p&gt;

&lt;p&gt;Async-await &lt;em&gt;is&lt;/em&gt; nice, which is why we&amp;rsquo;re adding it to Dart. It makes it a lot
easier to &lt;em&gt;write&lt;/em&gt; asynchronous code. You know a &amp;ldquo;but&amp;rdquo; is coming. It is.
&lt;em&gt;But&amp;hellip;&lt;/em&gt; you still have divided the world in two. Those async functions are
easier to write, but &lt;em&gt;they&amp;rsquo;re still async functions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ve still got two colors. Async-await solves annoying rule #4: they make red
functions not much worse to call than blue ones. But all of the other rules are
still there:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Synchronous functions return values, async ones return &lt;code&gt;Task&amp;lt;T&amp;gt;&lt;/code&gt; (or
&lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt; in Dart) wrappers around the value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sync functions are just called, async ones need an &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you call an async function you&amp;rsquo;ve got this wrapper object when you
actually want the &lt;code&gt;T&lt;/code&gt;. You can&amp;rsquo;t unwrap it unless you make &lt;em&gt;your&lt;/em&gt; function
async and await it. (But see below.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Aside from a liberal garnish of &lt;code&gt;await&lt;/code&gt;, we did at least fix this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;C#&amp;lsquo;s core library is actually older than async so I guess they never had
this problem.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It &lt;em&gt;is&lt;/em&gt; better. I will take async-await over bare callbacks or futures any day
of the week. But we&amp;rsquo;re lying to ourselves if we think all of our troubles are
gone. As soon as you start trying to write higher-order functions, or reuse
code, you&amp;rsquo;re right back to realizing color is still there, bleeding all over
your codebase.&lt;/p&gt;

&lt;h2&gt;What language &lt;em&gt;isn&amp;rsquo;t&lt;/em&gt; colored?&lt;/h2&gt;

&lt;p&gt;So JS, Dart, C#, and Python have this problem. CoffeeScript and most other
languages that compile to JS do too (which is why Dart inherited it). I &lt;em&gt;think&lt;/em&gt;
even ClojureScript has this issue even though they&amp;rsquo;ve tried really hard to push
against it with their &lt;a href=&quot;https://github.com/clojure/core.async&quot;&gt;core.async&lt;/a&gt; stuff.&lt;/p&gt;

&lt;p&gt;Wanna know one that doesn&amp;rsquo;t? &lt;em&gt;Java.&lt;/em&gt; I know right? How often do you get to say,
&amp;ldquo;Yeah, Java is the one that really does this right.&amp;rdquo;? But there you go. In
their defense, they are actively trying to correct this oversight by moving to
futures and async IO. It&amp;rsquo;s like a race to the bottom.&lt;/p&gt;

&lt;p&gt;C# also actually &lt;em&gt;can&lt;/em&gt; avoid this problem too. They opted &lt;em&gt;in&lt;/em&gt; to having color.
Before they added async-await and all of the &lt;code&gt;Task&amp;lt;T&amp;gt;&lt;/code&gt; stuff, you just used
regular sync API calls. Three more languages that don&amp;rsquo;t have this problem: Go,
Lua, and Ruby.&lt;/p&gt;

&lt;p&gt;Any guess what they have in common?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Threads.&lt;/em&gt; Or, more precisely: &lt;em&gt;multiple independent callstacks that &lt;a href=&quot;/2013/01/13/iteration-inside-and-out/&quot;&gt;can be
switched between&lt;/a&gt;&lt;/em&gt;. It isn&amp;rsquo;t strictly necessary for them to be operating
system threads. Goroutines in Go, coroutines in Lua, and fibers in Ruby are
perfectly adequate.&lt;/p&gt;

&lt;p&gt;(That&amp;rsquo;s why C# has that little caveat. You can avoid the pain of async in C# by
using threads.)&lt;/p&gt;

&lt;h2&gt;Remembrance of operations past&lt;/h2&gt;

&lt;p&gt;The fundamental problem is &amp;ldquo;How do you pick up where you left off when an
operation completes&amp;rdquo;? You&amp;rsquo;ve built up some big callstack and then you call some
IO operation. For performance, that operation uses the operating system&amp;rsquo;s
underlying asynchronous API. You &lt;em&gt;cannot&lt;/em&gt; wait for it to complete because it
won&amp;rsquo;t. You have to return all the way back to your language&amp;rsquo;s event loop and
give the OS some time to spin before it will be done.&lt;/p&gt;

&lt;p&gt;Once it is, you need to resume what you were doing. The usual way a language
&amp;ldquo;remembers where it is&amp;rdquo; is the &lt;em&gt;callstack&lt;/em&gt;. That tracks all of the functions
that are currently being invoked and where the instruction pointer is in each
one.&lt;/p&gt;

&lt;p&gt;But to do async IO, you have to unwind discard the entire C callstack. Kind of
a Catch-22. You can do super fast IO, you just can&amp;rsquo;t do anything with the
result! Every language that has async IO in its bowels&amp;mdash;or in the case of
JS, the browser&amp;rsquo;s event loop&amp;mdash;copes with this in some way.&lt;/p&gt;

&lt;p&gt;Node with its ever-marching-to-the-right callbacks stuffs all of those
callframes in closures. When you do:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;makeSundae&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;scoopIceCream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;iceCream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;warmUpCaramel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;caramel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pourOnIceCream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;iceCream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;caramel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each of those function expressions &lt;em&gt;closes&lt;/em&gt; over all of its surrounding
context. That moves parameters like &lt;code&gt;iceCream&lt;/code&gt; and &lt;code&gt;caramel&lt;/code&gt; off the callstack
and onto the heap. When the outer function returns and the callstack is
trashed, it&amp;rsquo;s cool. That data is still floating around the heap.&lt;/p&gt;

&lt;p&gt;The problem is you have to &lt;em&gt;manually&lt;/em&gt; reify every damn one of these steps.
There&amp;rsquo;s actually a name for this transformation: &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuation-passing_style&quot;&gt;&lt;em&gt;continuation-passing
style&lt;/em&gt;&lt;/a&gt;. It was invented by language hackers in the 70s as an intermediate
representation to use in the guts of their compilers. It&amp;rsquo;s a really bizarro way
to represent code that happens to make some compiler optimizations easier to
do.&lt;/p&gt;

&lt;p&gt;No one ever for a second thought that a programmer would &lt;em&gt;write actual code
like that&lt;/em&gt;. And then Node came along and all of the sudden here we are
pretending to be compiler back-ends. Where did we go wrong?&lt;/p&gt;

&lt;p&gt;Note that promises and futures don&amp;rsquo;t actually buy you anything, either. If
you&amp;rsquo;ve used them, you know you&amp;rsquo;re still hand-creating giant piles of function
literals. You&amp;rsquo;re just passing them to &lt;code&gt;.then()&lt;/code&gt; instead of to the asynchronous
function itself.&lt;/p&gt;

&lt;h2&gt;Awaiting a generated solution&lt;/h2&gt;

&lt;p&gt;Async-await &lt;em&gt;does&lt;/em&gt; help. If you peel back your compiler&amp;rsquo;s skull and see what
it&amp;rsquo;s doing when it hits an &lt;code&gt;await&lt;/code&gt; call you&amp;rsquo;d see it actually doing the
CPS-transform. That&amp;rsquo;s &lt;em&gt;why&lt;/em&gt; you need to use &lt;code&gt;await&lt;/code&gt; in C#: it&amp;rsquo;s a clue to the
compiler to say, &amp;ldquo;break the function in half here&amp;rdquo;. Everything after the
&lt;code&gt;await&lt;/code&gt; gets hoisted into a new function that it synthesizes on your behalf.&lt;/p&gt;

&lt;p&gt;This is why async-await didn&amp;rsquo;t need any &lt;em&gt;runtime&lt;/em&gt; support in the .NET
framework. The compiler compiles it away to a series of chained closures that
it can already handle. (Interestingly, closures themselves also don&amp;rsquo;t need
runtime support. &lt;em&gt;They&lt;/em&gt; get compiled to anonymous classes. In C#, closures
really &lt;em&gt;are&lt;/em&gt; a &lt;a href=&quot;http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent&quot;&gt;poor man&amp;rsquo;s objects&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;You might be wondering when I&amp;rsquo;m going to bring up generators. Does your
language have a &lt;code&gt;yield&lt;/code&gt; keyword? Then it can do something very similar.&lt;/p&gt;

&lt;p&gt;(In fact, I &lt;em&gt;believe&lt;/em&gt; generators and async-await are isomorphic. I&amp;rsquo;ve got a bit
of code floating around in some dark corner of my hard disc that implements a
generator-style game loop using only async-await.)&lt;/p&gt;

&lt;p&gt;Where was I? Oh, right. So with callbacks, promises, async-await, and
generators, you ultimately end up taking your asynchronous function and
smearing it out into a bunch of closures that live over in the heap.&lt;/p&gt;

&lt;p&gt;Your function passes the outermost one into the runtime. When the event loop or
IO operation is done, it invokes that function and you pick up where you left
off. But that means everything above you &lt;em&gt;also&lt;/em&gt; has to return. You still have
to unwind the &lt;em&gt;whole&lt;/em&gt; stack.&lt;/p&gt;

&lt;p&gt;This is where the &amp;ldquo;red functions can only be called by red functions&amp;rdquo; rule
comes from. You have to closurify the entire callstack all the way back to
&lt;code&gt;main()&lt;/code&gt; or the event handler.&lt;/p&gt;

&lt;h2&gt;Reified callstacks&lt;/h2&gt;

&lt;p&gt;But if you have threads (green- or OS-level), you don&amp;rsquo;t need to do that. You
can just suspend the entire thread and hop straight back to the OS or event
loop &lt;em&gt;without having to return from all of those functions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Go is the language that does this most beautifully in my opinion. As soon as
you do any IO operation, it just parks that goroutine and resumes any other
ones that aren&amp;rsquo;t blocked on IO.&lt;/p&gt;

&lt;p&gt;If you look at the IO operations in the standard library, they seem
synchronous. In other words, they just do work and then return a result when
they are done. But it&amp;rsquo;s not that they&amp;rsquo;re synchronous in the sense that it would
mean in JavaScript. Other Go code can run while one of these operations is
pending. It&amp;rsquo;s that Go has &lt;em&gt;eliminated the distinction between synchronous and
asynchronous code&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Concurrency in Go is a facet of how &lt;em&gt;you&lt;/em&gt; choose to model your program, and not
a color seared into each function in the standard library. This means all of
the pain of the five rules I mentioned above is completely and totally
eliminated.&lt;/p&gt;

&lt;p&gt;So, the next time you start telling me about some new hot language and how
awesome its concurrency story is because it has asynchronous APIs, now you&amp;rsquo;ll
know why I start grinding my teeth. Because it means you&amp;rsquo;re right back to red
functions and blue ones.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes"/>
    <title>Rooms and Mazes: A Procedural Dungeon Generator</title>
    <published>2014-12-21T00:00:00-08:00</published>
    <updated>2014-12-21T00:00:00-08:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;style&gt;
canvas {
  background: #222;
  display: inline-block;
  max-width: 100%;
}
&lt;/style&gt;

&lt;p&gt;Several months ago I promised a follow-up to my previous blog post about &lt;a href=&quot;/2014/07/15/a-turn-based-game-loop/&quot;&gt;turn-based game loops&lt;/a&gt; in &lt;a href=&quot;https://github.com/munificent/hauberk&quot;&gt;my roguelike&lt;/a&gt;. Then I got completely sidetracked by &lt;a href=&quot;/2014/11/03/bringing-my-web-book-to-print-and-ebook/&quot;&gt;self-publishing&lt;/a&gt; &lt;a href=&quot;/2014/11/20/how-my-book-launch-went/&quot;&gt;my book&lt;/a&gt;, &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;&lt;em&gt;Game Programming Patterns&lt;/em&gt;&lt;/a&gt;, and forgot all about it. I totally left you hanging.&lt;/p&gt;

&lt;p&gt;Well, I finally got some time to think about my roguelike again and today, I&amp;rsquo;m here to&amp;hellip; keep you hanging. Alas, you are at the mercy of my wandering attention span! Instead of game loops, today we&amp;rsquo;re going to talk about possibly the most fun and challenging part of making a roguelike: generating dungeons!&lt;/p&gt;

&lt;p&gt;Go ahead and click the little box below to see what we end up with:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;enchilada&quot; width=&quot;570&quot; height=&quot;390&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Click it again to restart it.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Pretty neat, huh? If you want to skip the prose, the code is &lt;a href=&quot;https://github.com/munificent/hauberk/blob/db360d9efa714efb6d937c31953ef849c7394a39/lib/src/content/dungeon.dart&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of my earliest memories of computing is a maze generator running on my family&amp;rsquo;s Apple IIe. It filled the screen with a grid of green squares, then incrementally cut holes in the walls. Eventually, every square of the grid was connected and the screen was filled with a complete, perfect maze.&lt;/p&gt;

&lt;p&gt;My little home computer could create something that had deep structure&amp;mdash;every square of the maze could be reached from any other&amp;mdash;and yet it seemed to be chaotic&amp;mdash;it carved at random and every maze was different. This was enough to blow my ten-year-old mind. It still kind of does today.&lt;/p&gt;

&lt;h2&gt;What&amp;rsquo;s in a dungeon?&lt;/h2&gt;

&lt;p&gt;Procedural generation&amp;mdash;having the game build stuff randomly instead of using hand-authored content&amp;mdash;is amazing when it works well. You get a ton of replayability because the game is different every time. As the person implementing the game, you also get the critical feature of not knowing what you&amp;rsquo;re going to get even though you wrote the code. The game can surprise &lt;em&gt;you&lt;/em&gt; too.&lt;/p&gt;

&lt;p&gt;People get into procedural generation because it seems easier. Hand-authoring content is obviously a lot of work. If you want your game to have a hundred levels, you have to make a hundred things. But make one little random level generator and you can have a hundred levels, a thousand, or a million, for free!&lt;/p&gt;

&lt;p&gt;Alas, it doesn&amp;rsquo;t &lt;em&gt;quite&lt;/em&gt; work out that way. You see, &lt;em&gt;defining the procedure&lt;/em&gt; is a hell of a lot harder than just sitting down and banging out some content. You have to take some very nebulous, artistic chunk of your brain, figure out precisely what it&amp;rsquo;s doing, and translate that to code. You&amp;rsquo;re coding a simulation of yourself.&lt;/p&gt;

&lt;p&gt;It must balance a number of technical and aesthetic constraints. For mine, I focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It needs to be &lt;strong&gt;fairly efficient.&lt;/strong&gt; The generator only runs when the player enters a new level, so it doesn&amp;rsquo;t have to be as &lt;em&gt;super&lt;/em&gt; fast, but I still don&amp;rsquo;t want a several second pause giving the player time to question whether they should be playing a game or doing something more productive with their life.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The dungeon needs to be &lt;strong&gt;connected.&lt;/strong&gt; Like the mazes on my old green-screen Apple, that means from any point in the dungeon, there is a way&amp;mdash;possibly circuitous&amp;mdash;to any other point.&lt;/p&gt;

&lt;p&gt;This is vital because if player has to complete a quest like &amp;ldquo;find the magic chalice&amp;rdquo; or &amp;ldquo;kill the cockatrice&amp;rdquo;, it&amp;rsquo;s pretty cruel if the dungeon drops that in some walled-off room the player can&amp;rsquo;t get to. It also avoids wasting time generating and populating areas the player can never see.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moreso, I want dungeons to &lt;strong&gt;not be perfect.&lt;/strong&gt; &amp;ldquo;Perfect&amp;rdquo; in the context of mazes and graphs (which are synonymous) means there is &lt;em&gt;only one&lt;/em&gt; path between any two points. If you flatten out all of the windy passages, you&amp;rsquo;ll discover your twisty maze is really just a tree all crumpled up. Passageways branch but never merge. &lt;em&gt;Im&lt;/em&gt;-perfect mazes have loops and cycles&amp;mdash;multiple paths from A to B.&lt;/p&gt;

&lt;p&gt;This is a gameplay constraint, not a technical one. You could make a roguelike with perfect dungeons, and many simple roguelikes do that because generators for those are easier to design and implement.&lt;/p&gt;

&lt;p&gt;But I find them less fun to play. When you hit a dead end (which is often), you have to do a lot of backtracking to get to a new area to explore. You can&amp;rsquo;t circle around to avoid certain enemies, or sneak out a back passage. Neither can the bad guys, for that matter.&lt;/p&gt;

&lt;p&gt;Fundamentally, games are about making decisions from a set of alternatives. At a literal level, perfect dungeons only give you one path to choose from.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I want &lt;strong&gt;open rooms.&lt;/strong&gt; I could make dungeons just be nothing but mazes of narrow passages, but then you could never get surrounded by a horde of monsters. It would feel claustrophic and kill a bunch of interesting combat tactics.&lt;/p&gt;

&lt;p&gt;Wide open areas are critical for area effect spells, and big dramatic battles. They also provide space for interesting decorations and themed areas. Vaults, pits, traps, treasure rooms, etc. Rooms are the high points of the hero&amp;rsquo;s journey.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I want &lt;strong&gt;passageways.&lt;/strong&gt; At the same time, I don&amp;rsquo;t want the dungeon to &lt;em&gt;just&lt;/em&gt; be rooms. There are some games that create levels this way where doors directly join room to room. It works OK, but I find it a bit monotonous. I like the player feeling confined part of the time, and having narrow corridors that the player can draw monsters into is a key tactic in the game.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All of this needs to be &lt;strong&gt;tunable.&lt;/strong&gt; Many roguelikes have one huge multi-floor dungeon where depths vary in difficulty but not much else. My game is different. It has a number of different &lt;em&gt;areas&lt;/em&gt;. Each has its own look and feel. Some may be small and cramped, others spacious and orderly.&lt;/p&gt;

&lt;p&gt;I solve this partially by having multiple distinct dungeon generation algorithms. Outdoor areas use an entirely different process. (I should probably write about that too sometime. Look, another unfulfilled promise!)
But coding a new dungeon generator from scratch for &lt;em&gt;every&lt;/em&gt; area is a huge time sink. Instead, I want the generator to have a bunch of knobs and levers I can tweak so I can make a number of areas that share the same code but have their own feel.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;A room with a view&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve been working on this game pretty much forever (it&amp;rsquo;s gone through four different implementation languages!) and I&amp;rsquo;ve tried a number of different dungeon generators. My main source of inspiration is a game called &lt;a href=&quot;http://rephial.org/&quot;&gt;Angband&lt;/a&gt;. The only thing I&amp;rsquo;ve sunk more of my life into than working on my game is playing that one.&lt;/p&gt;

&lt;p&gt;Angband is fantastically old. When it forked off of Moria, Nancy Kerrigan had just taken a round of melee damage from a club-wielding troll. On machines of that time, it was much harder to make a fast dungeon generator, and Angband&amp;rsquo;s is pretty simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sprinkle a bunch of randomly located, non-overlapping rooms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Draw random corridors to connect them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To ensure rooms don&amp;rsquo;t overlap, I just discard a room if it collides with any previously placed one. To avoid a possible infinite loop, instead of trying until a certain number of rooms are successfully &lt;em&gt;placed&lt;/em&gt;, I do a fixed number of &lt;em&gt;attempts&lt;/em&gt; to place rooms. Failure becomes more common as the dungeon gets fuller&amp;mdash;after all, you can only fit so many rooms in a given area&amp;mdash;but tuning this gives you some control over room density, like so:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;rooms&quot; width=&quot;570&quot; height=&quot;390&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;label for=&quot;attempts&quot;&gt;Attempts:&lt;/label&gt;
  &lt;input type=&quot;range&quot; id=&quot;attempts&quot; min=&quot;10&quot; value=&quot;200&quot; max=&quot;1000&quot;&gt;
  &lt;output for=&quot;attempts&quot; id=&quot;attempts-output&quot;&gt;200&lt;/output&gt;
&lt;/figure&gt;

&lt;h2&gt;A dark and twisty passageway&lt;/h2&gt;

&lt;p&gt;Most of the dungeon generators I&amp;rsquo;ve written start with this. The hard part, by far, is making good passageways to connect them. That&amp;rsquo;s really what this post is about&amp;mdash;a neat way to solve that problem.&lt;/p&gt;

&lt;p&gt;Angband&amp;rsquo;s solution is brute force but surprisingly effective. It picks a pair of rooms&amp;mdash;completely ignoring how far apart they are&amp;mdash;and starts a passageway that wanders randomly from one (hopefully) to the other. It&amp;rsquo;s got a few clever checks to keep things from overlapping too much but passageways can and do cut through other rooms, cross other passages or dead end.&lt;/p&gt;

&lt;p&gt;I tried implementing that a number of times but (likely failures on my part) never got to something I really liked. The corridors I ended up with always looked too straight, or overlapped other stuff in unattractive ways.&lt;/p&gt;

&lt;p&gt;Then, a few months ago, I stumbled onto a &lt;a href=&quot;http://www.reddit.com/r/roguelikedev/comments/2brhl8/screenshot_saturday_08/cj87umz&quot;&gt;description of a dungeon generator&lt;/a&gt; by &lt;a href=&quot;http://www.reddit.com/user/FastAsUcan&quot;&gt;u/FastAsUcan&lt;/a&gt; on the &lt;a href=&quot;http://www.reddit.com/r/roguelikedev/&quot;&gt;/r/roguelikedev&lt;/a&gt; subreddit. His generator, &lt;a href=&quot;http://www.odedwelgreen.com/karcero/&quot;&gt;Karcero&lt;/a&gt;, is based on &lt;a href=&quot;http://weblog.jamisbuck.org/&quot;&gt;Jamis Buck&amp;rsquo;s&lt;/a&gt; dungeon generator. If you&amp;rsquo;ve ever done any procedural dungeon generation, you know&amp;mdash;or should know&amp;mdash;who Buck is. He&amp;rsquo;s got a ton of great articles on random mazes.&lt;/p&gt;

&lt;p&gt;Years ago, I remember seeing an actual &lt;a href=&quot;http://www.myth-weavers.com/generate_dungeon.php&quot;&gt;dungeon generator&lt;/a&gt; he wrote for use with pen-and-paper Dungeons &amp;amp; Dragons. Unlike most of his maze stuff, this had actual rooms, and the results looked great.&lt;/p&gt;

&lt;p&gt;But, at the time, I didn&amp;rsquo;t know how it &lt;em&gt;worked&lt;/em&gt;. How do you go from mazes to open winding corridors and rooms? I tucked this open question away in the corner of my mind and immediately forgot about it.&lt;/p&gt;

&lt;p&gt;The post by FastAsUcan provides the answer. It works like so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Make a perfect maze. There are a number of different algorithms for this, but they&amp;rsquo;re all fairly straightforward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make the maze &lt;em&gt;sparse&lt;/em&gt;. Find dead end passages and fill them back in with solid rock.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick some of the remaining dead ends and cut holes in them to adjacent walls. This makes the maze imperfect. (Remember, this is a good thing!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create rooms and find good locations to place them. &amp;ldquo;Good&amp;rdquo; here means not overlapping the maze but &lt;em&gt;near&lt;/em&gt; it so you can add a door and connect it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The magic step, and the piece I was missing, is &lt;em&gt;sparseness&lt;/em&gt;. A normal maze fills every single square of the world, leaving no areas where you can fit a room. The trick that Jamis and FastAsUcan do here is to carve the whole maze and then &lt;em&gt;uncarve&lt;/em&gt; the dead ends.&lt;/p&gt;

&lt;p&gt;Doing that is actually pretty easy. A dead end is just a tile that has walls on three sides. When you find one of those, you fill that tile back in. That may in turn make the tile it connects to a dead end. Keep doing this until you run out of dead ends and you&amp;rsquo;ll end up with lots of solid area where rooms can be placed.&lt;/p&gt;

&lt;p&gt;Of course, if you do that starting with a perfect maze and run to completion, you&amp;rsquo;ll erase the whole maze! A perfect maze has no loops so &lt;em&gt;everything&lt;/em&gt; is a dead end if you follow passages long enough. Jamis&amp;rsquo; solution is to not erase &lt;em&gt;all&lt;/em&gt; of the dead ends, just some. It stops after a while. Something like this:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;dead-ends&quot; width=&quot;570&quot; height=&quot;390&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;label for=&quot;dead-end-open&quot;&gt;Corridors to leave:&lt;/label&gt;
  &lt;input type=&quot;range&quot; id=&quot;dead-end-open&quot; min=&quot;1&quot; value=&quot;1000&quot; max=&quot;3000&quot;&gt;
  &lt;output for=&quot;dead-end-open&quot; id=&quot;dead-end-open-output&quot;&gt;1000&lt;/output&gt;
&lt;/figure&gt;

&lt;p&gt;Once you do that, you can start placing rooms. The process Jamis uses for this is interesting. He picks a room size and then tries to place it on every single location in the dungeon. Any location that overlaps a room or passageway is discarded. The remaining positions are &amp;ldquo;ranked&amp;rdquo; where rooms that are near passageways are better. It then picks the best position and places the room there, and puts some doors between the room and the passage.&lt;/p&gt;

&lt;p&gt;Rinse, lather, repeat and you&amp;rsquo;ve got yourself a dungeon.&lt;/p&gt;

&lt;h2&gt;Rooms &lt;em&gt;then&lt;/em&gt; mazes&lt;/h2&gt;

&lt;p&gt;I went ahead and coded this up exactly as described. It went OK, but I found that the process of placing rooms was pretty slow. It works well for dungeons of the small size you do for a tabletop role-playing game, but not so much at the scale of a computer roguelike.&lt;/p&gt;

&lt;p&gt;So, I did some tinkering and came up with a slight variation. My contribution is pretty minor, but I thought it would be worth writing down. (Honestly, I just think it&amp;rsquo;s fun to watch animated dungeon generators, and the prose is pure fluff.)&lt;/p&gt;

&lt;p&gt;Where Buck and Karcero start with the maze and then add the rooms, mine does things in the opposite order. First, it places a bunch of random rooms. Then, it iterates over every tile in the dungeon. When it finds a solid one where an open area &lt;em&gt;could&lt;/em&gt; be, it starts running a maze generator at that point.&lt;/p&gt;

&lt;p&gt;Maze generators work by incrementally carving passages while avoiding cutting into an already open area. That&amp;rsquo;s how you ensure the maze only has one solution. If you let it carve into existing passages, you&amp;rsquo;d get loops.&lt;/p&gt;

&lt;p&gt;This is conveniently exactly what you need to let the maze grow and fill the odd shaped areas that surround the rooms. In other words, a maze generator is a randomized &lt;a href=&quot;http://en.wikipedia.org/wiki/Flood_fill&quot;&gt;flood fill&lt;/a&gt; algorithm. Run this on every solid region between the rooms and we&amp;rsquo;re left with the entire dungeon packed full of disconnected rooms and mazes.&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;maze-fill&quot; width=&quot;570&quot; height=&quot;390&quot;&gt;
      Sorry, you need canvas support for this demo.
  &lt;/canvas&gt;
  &lt;figcaption&gt;
    Each color here represents a different region of connected tiles.
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Looking for a connection&lt;/h2&gt;

&lt;p&gt;All that remains is to stitch those back together into a single continuous dungeon. Fortunately, that&amp;rsquo;s pretty easy to do. The room generator chooses odd sizes and positions for rooms so they are aligned with the mazes. Those in turn fill in all of the unused area, so we&amp;rsquo;re assured that each unconnected region is only a single tile away from its neighbors.&lt;/p&gt;

&lt;p&gt;After filling in the rooms and mazes, we find all of those possible &lt;em&gt;connectors&lt;/em&gt;. These are tiles that are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Solid rock.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adjacent to two regions of different colors.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here they are highlighted:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;connectors&quot; width=&quot;570&quot; height=&quot;390&quot;&gt;
      Sorry, you need canvas support for this demo.
  &lt;/canvas&gt;
&lt;/figure&gt;

&lt;p&gt;We use these to tie the regions together. Normally we think of the entire dungeon as a graph with each tile a vertex, but we&amp;rsquo;re going to go up a level of abstraction. Now, we treat each &lt;em&gt;region&lt;/em&gt; of tiles as a single vertex and each connector as an edge between them.&lt;/p&gt;

&lt;p&gt;If we use &lt;em&gt;all&lt;/em&gt; of the connectors, our dungeon would be way too densely connected. Instead, we carve through just the connectors we need to get each region connected to the whole &lt;em&gt;once&lt;/em&gt;. In fancy terms, we&amp;rsquo;re finding a &lt;a href=&quot;http://en.wikipedia.org/wiki/Spanning_tree&quot;&gt;&lt;em&gt;spanning tree&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The process is pretty straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pick a random room to be the main region.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pick a random connector that touches the main region and open it up.&lt;/strong&gt; In the demo, it does that by placing a door, but you can do an open passageway, locked door, or magical wardrobe. Be creative.&lt;/p&gt;

&lt;p&gt;Note that this process is agnostic about rooms and mazes. It just deals in
&amp;ldquo;regions&amp;rdquo;. That means it can connect rooms directly to other rooms sometimes. You can avoid that if you want, but I find the resulting dungeons more fun to play.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The connected region is now part of the main one. Unify it.&lt;/strong&gt; In the demo, I use a little flood fill algorithm to color in the newly merged region because it looks pretty. In a real implementation, you don&amp;rsquo;t need to mess with tiles. Just make a little data structure that tracks &amp;ldquo;region X is now merged&amp;rdquo;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remove any extraneous connectors.&lt;/strong&gt; There are likely other existing connectors that connect the two regions that just merged. Since they no longer connect two separate regions and we want a spanning tree, discard them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If there are still connectors left, go to #2.&lt;/strong&gt; Any remaining connectors imply that there is still at least one disconnected region. Keep looping until all of the unconnected regions are merged into the main one.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Earlier, I said that I don&amp;rsquo;t want a perfect dungeon because they make for crappy gameplay. But, since this creates a spanning tree, that&amp;rsquo;s exactly what we&amp;rsquo;ve got. We only allow a single connector between any two regions so our dungeon &lt;em&gt;is&lt;/em&gt; a tree and there&amp;rsquo;s only a single path between any two points.&lt;/p&gt;

&lt;p&gt;Fixing that is pretty simple. In step 3, when we cull the unneeded connectors, we give them a &lt;em&gt;slight&lt;/em&gt; chance of being opened up. Something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rng&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oneIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_carve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CELL_DOOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This occasionally carves an extra opening between regions. That gives us the imperfect loops we want to make the dungeon more fun to play in. Note that this is also easily tunable. If we make the chance more likely, we get more densely connected dungeons.&lt;/p&gt;

&lt;h2&gt;Uncarving&lt;/h2&gt;

&lt;p&gt;If we stop here, we&amp;rsquo;ll get dungeons that are packed chock full of maze corridors, most of which are dead ends. That has a certain sadistic appeal, but isn&amp;rsquo;t exactly what I&amp;rsquo;m going for. The last remaining step is the &amp;ldquo;sparseness&amp;rdquo; pass described earlier.&lt;/p&gt;

&lt;p&gt;Now that we&amp;rsquo;ve got all of our rooms connected to each other, we can remove all of the dead ends in the maze. When we do that, the mazes are reduced to just the winding set of passageways needed to connect the rooms to each other. Every corridor is guaranteed to go somewhere interesting.&lt;/p&gt;

&lt;h2&gt;What we ended up with&lt;/h2&gt;

&lt;p&gt;In summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Place a bunch of random non-overlapping rooms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fill in the remaining solid regions with mazes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect each of the mazes and rooms to their neighbors, with a chance to add some extra connections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove all of the dead ends.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I&amp;rsquo;m pretty happy with it so far. It&amp;rsquo;s not perfect, though. It tends to produce annoyingly windy passages between rooms. You can tune that by tweaking your maze generation algorithm, but making the passageways less windy tends to make them wander to the edge of the dungeon, which has its own strange look.&lt;/p&gt;

&lt;p&gt;The fact that rooms and mazes are aligned to odd boundaries makes things simpler and helps fill it in nicely, but it does give the dungeon a bit of an artificially aligned look. But, overall, it&amp;rsquo;s an improvement over what I had before, and the dungeons it makes seem to be pretty fun to play.&lt;/p&gt;

&lt;p&gt;If you want to see for yourself, you can play the game &lt;a href=&quot;http://munificent.github.io/hauberk/&quot;&gt;right in your browser&lt;/a&gt;. The code for these demos is &lt;a href=&quot;https://github.com/munificent/rooms-and-mazes&quot;&gt;here&lt;/a&gt;, but it&amp;rsquo;s pretty gnarly. Making them animated adds a lot of complexity. Instead, &lt;a href=&quot;https://github.com/munificent/hauberk/blob/db360d9efa714efb6d937c31953ef849c7394a39/lib/src/content/dungeon.dart&quot;&gt;here&lt;/a&gt; is the much cleaner implementation my game uses.&lt;/p&gt;

&lt;p&gt;As a bonus for making it this far, here&amp;rsquo;s a super dense giant dungeon. I find it hypnotic:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;giant&quot; width=&quot;570&quot; height=&quot;390&quot;&gt;
      Sorry, you need canvas support for this demo.
  &lt;/canvas&gt;
&lt;/figure&gt;

&lt;script type=&quot;application/dart&quot; src=&quot;/code/2014-12-21-rooms-and-mazes/main.dart&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/code/2014-12-21-rooms-and-mazes/packages/browser/dart.js&quot;&gt;&lt;/script&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2014/11/20/how-my-book-launch-went</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2014/11/20/how-my-book-launch-went"/>
    <title>How My Book Launch Went</title>
    <published>2014-11-20T00:00:00-08:00</published>
    <updated>2014-11-20T00:00:00-08:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;p&gt;Greetings, superfans! When we &lt;a href=&quot;/2014/11/03/bringing-my-web-book-to-print-and-ebook/&quot;&gt;last tuned in&lt;/a&gt;, I was just about to &amp;ldquo;launch&amp;rdquo; &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;my self-published book&lt;/a&gt;. I put that in quotes because it&amp;rsquo;s an awfully serious-sounding word for what was really just doing some clicking on my laptop. If my last post was the climax of my book writing adventure, consider this the denouement. You&amp;rsquo;ve been with me this long, it&amp;rsquo;s the least I can do.&lt;/p&gt;

&lt;p&gt;I do hold back one detail, though: while I talk about sales here, I won&amp;rsquo;t be putting cash numbers on it. If you try hard enough, you can calculate them yourself, but I feel weird sharing financial details. Strangely, it&amp;rsquo;s not because I&amp;rsquo;m shy about &lt;em&gt;strangers&lt;/em&gt; knowing it as much as I am friends and family. So much room for awkwardness there.&lt;/p&gt;

&lt;h2&gt;I am a Marketer and I do Marketer-y Things&lt;/h2&gt;

&lt;p&gt;As I mentioned before, I decided to self-publish about halfway through writing the manuscript. That meant I had to wear all of the hats that a publisher has dedicated noggins for: editor, designer, proofreader, and&amp;hellip; marketer. This last one is the least fun for me, but I know it&amp;rsquo;s important.&lt;/p&gt;

&lt;p&gt;I read a bit online and what a lot of people said was that email lists are gold. &lt;em&gt;I&lt;/em&gt; like that they are pull-based instead of push-based. Instead of jamming myself and my book down strangers&amp;rsquo; throats, they sign up of their own volition. I only get in touch with the people who actually want to hear from me.&lt;/p&gt;

&lt;p&gt;So I created a &lt;a href=&quot;http://mailchimp.com/&quot;&gt;MailChimp&lt;/a&gt; account&amp;mdash;chosen over other mailing list providers mainly because of their cute logo&amp;mdash;and slapped a little &amp;ldquo;sign up!&amp;rdquo; form on every page of the site. Whenever I put a new chapter online, I got a traffic bump and some fraction of those people were kind or foolhardy enough to grant me their email address.&lt;/p&gt;

&lt;p&gt;I did this pretty early in the writing process so that I could give it time to grow before the book was complete. By putting the whole book online and releasing it chapterly (like a Dickens serial for the Internet age) I had amassed a surprisingly large list by the time I was ready to &lt;strike&gt;try to squeeze money out of them&lt;/strike&gt; tell them my book was complete. Around 8,000 people, which still seems like a crazy large number to me.&lt;/p&gt;

&lt;p&gt;I also, despite &lt;a href=&quot;https://twitter.com/munificentbob&quot;&gt;the content of my tweets&lt;/a&gt;, managed to acquire a fair number of twitter friends. (I don&amp;rsquo;t like thinking of them &amp;ldquo;followers&amp;rdquo;. Celebutants and TEDx thought/cult leaders have &amp;ldquo;followers&amp;rdquo;. I just have Internet pals.)&lt;/p&gt;

&lt;h2&gt;A New Front Page&lt;/h2&gt;

&lt;p&gt;Now that the book is a &lt;em&gt;product&lt;/em&gt; as much as it is a &lt;em&gt;web site&lt;/em&gt;, I redid the front page to highlight both of those. It still, of course, links to the web version. And, &lt;em&gt;of course&lt;/em&gt;, the entire contents of the book are still readable on the web. But I also added links to the various sites where you could get the print version, Kindle, and EPUB.&lt;/p&gt;

&lt;p&gt;I wanted to emphasize the &amp;ldquo;bookyness&amp;rdquo; of it, the physicality, so I got out my camera and my macro lens and took a bunch of honest-to-God photos of it:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/cover-shoot.jpg&quot;&gt;
  &lt;figcaption&gt;Wait&amp;hellip; if the camera is in the photo, how did I take &lt;em&gt;this&lt;/em&gt; shot?&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There&amp;rsquo;s something weird and meta about taking a picture of myself taking photos of a book whose cover I designed using a photo I took of an illustration I drew. I should take a picture of myself writing this blog post just to go full Inception.&lt;/p&gt;

&lt;p&gt;Next, I spent way too long coming up with a design and text for the front page. Seriously, it took me as long to make what is effectively a glorified list of hyperlinks as it did to write, illustrate, and edit a full chapter of the book. I think it&amp;rsquo;s worth it, though. The front page is the reader&amp;rsquo;s first impression of the book. If I make you feel that page is beautiful and high quality, it&amp;rsquo;s a short hop to having faith that the inside of the book is too.&lt;/p&gt;

&lt;p&gt;I ended up with this:&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;http://gameprogrammingpatterns.com&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/new-site.jpg&quot;&gt;&lt;/a&gt;
  &lt;figcaption&gt;Click to zoom!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;This Part of the Blog Post is About Writing a Blog Post&lt;/h2&gt;

&lt;p&gt;I feel a little squirmy writing this. Like I said, I&amp;rsquo;m uncomfortable with self-promotion. I hoped, wanted, to get a decent amount of&amp;hellip; attention? traffic? validation of my worth as a human? when I announced the for-sale versions of the book. Readers had been asking for them for a while, so I knew there would be some excitement just by saying, &amp;ldquo;Here they are.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;But that didn&amp;rsquo;t feel really newsworthy to me. There wasn&amp;rsquo;t much to discuss, just &amp;ldquo;here they are. moneys plz.&amp;rdquo; People like a story, and I like telling them, especially when the protagonist is yours truly. I&amp;rsquo;ve been really lucky to have a lot of encouragement on this project from readers, and I thought one way to say thanks would be to give a window into what the production process was like. It&amp;rsquo;s a side of book-making that I don&amp;rsquo;t see very much online.&lt;/p&gt;

&lt;p&gt;Also, it let me blather about fonts for six thousand words. Seriously, the &lt;a href=&quot;/2014/11/03/bringing-my-web-book-to-print-and-ebook/&quot;&gt;blog post&lt;/a&gt; I wrote about turning the manuscript into a physical book is longer than almost every chapter in the book. Clearly, I need an editor.&lt;/p&gt;

&lt;p&gt;This also took a lot of time&amp;mdash;about a week&amp;mdash;but I really enjoyed writing it all down. I did my best to make it an entertaining read. While I hoped it would drive traffic to the book, I did honestly want it to be a worthwhile read in and of itself. I believe that, when played well, life is a non-zero-sum game.&lt;/p&gt;

&lt;h2&gt;I &amp;lt;3 Filling Out Web Forms&lt;/h2&gt;

&lt;p&gt;I was ready to upload the new site, and the new blog post. All that was left was to actually make the book available. This involved uploading various files&amp;mdash;inside PDF for the print version, cover, EPUB file, MOBI file&amp;mdash;to various sites whose forms cover the full gamut of usability. Clicking the final &amp;ldquo;OK&amp;rdquo; on CreateSpace, Kindle Direct Publishing, and Smashwords was both nerve-wracking and anti-climactic.&lt;/p&gt;

&lt;p&gt;Then the waiting game. Most of these sites do various amounts of automated and manual validation that take time to process. I noticed a typo that forced me to re-upload to CreateSpace. Kindle found a couple of spelling errors (surprising given how many rounds of editing I&amp;rsquo;d done by now). Smashwords asked me to have an explicit cover page.&lt;/p&gt;

&lt;p&gt;Once those were all happy, the listings appeared. If you knew to look for them, you could have bought the book.&lt;/p&gt;

&lt;p&gt;CreateSpace and Smashwords also distribute to other sales channels (things like Lightning Source and book stores for the former; iBooks, Nook, Kobo, etc. for the latter). I wanted to wait for those sales channels to populate before I pulled the switch but&amp;hellip; well, I got impatient.&lt;/p&gt;

&lt;p&gt;As soon as I saw &lt;a href=&quot;http://www.amazon.com/gp/product/0990582906&quot;&gt;the Amazon page for my book&lt;/a&gt;, I just couldn&amp;rsquo;t wait any more. I pushed the new version of the site and the blog post. I wrote an email and blasted the mailing list. I tweeted. I mentioned it on G+.&lt;/p&gt;

&lt;p&gt;What I &lt;em&gt;didn&amp;rsquo;t&lt;/em&gt; do this time was post it to reddit. It felt a little too self-serving for how reddit rolls. I did post a link to the blog &lt;a href=&quot;https://news.ycombinator.com/item?id=8555285&quot;&gt;on Hacker News&lt;/a&gt; since that crowd is more accepting of self-promotion.&lt;/p&gt;

&lt;p&gt;I had tabs open for the Smashwords sales dashboard, CreateSpace royalties, Kindle Direct Publishing sales report, twitter, and Hacker News. I refreshed those suckers like my life depended on it.&lt;/p&gt;

&lt;h2&gt;Command, We Are Ready for Launch&lt;/h2&gt;

&lt;p&gt;This moment, as dumb as it sounds, was actually pretty stressful. A surprisingly large number of self-published books just sink to the depths leaving nary a ripple on the surface. You hear horror stories of writers whose novels sell &lt;em&gt;zero&lt;/em&gt; copies. Nonfiction is a lot easier, but I still had no idea if people really liked the book enough to drop real cash on it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Refresh refresh refresh refresh.&lt;/em&gt; A nervous sweat trickled down my neck.&lt;/p&gt;

&lt;p&gt;A few minutes later, Smashwords reported two sales. Holy shit! Someone bought the book! I was a professional writer!&lt;/p&gt;

&lt;p&gt;Then people started retweeting me. Someone posted a blurb about it &lt;a href=&quot;http://www.reddit.com/r/gamedev/comments/2l9hr0/game_programming_patterns_is_now_in_print/&quot;&gt;on the gamedev subreddit&lt;/a&gt; and someone else did &lt;a href=&quot;http://www.reddit.com/r/programming/comments/2l8v11/today_is_the_day_game_programming_patterns_now_in/&quot;&gt;on the programming subreddit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;People started saying super nice things! About me! It was awesome! Also, I was drinking in celebration at the same time so that multiplied all the good feelings.&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/cat.gif&quot;&gt;
  &lt;figcaption&gt;How I felt.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I feverishly replied to as many comments, tweets, and emails as I could. (All the while still refreshing the other tabs.) Eventually, I maxed out my serotonin levels and had to crash. Like some candy raver in an E puddle in the back of the chill-out room, I passed out, totally spent.&lt;/p&gt;

&lt;h2&gt;The Next Day&lt;/h2&gt;

&lt;p&gt;I woke up the next morning feeling like a kid on Christmas. A kid who wasn&amp;rsquo;t &lt;em&gt;entirely&lt;/em&gt; certain he&amp;rsquo;d been good enough for Santa to bring him presents. Morning coffee in hand, I opened up my laptop and checked all the dashboards.&lt;/p&gt;

&lt;p&gt;While I slept, I&amp;rsquo;d sold enough copies to pay off all of the expenses of the book. That isn&amp;rsquo;t actually &lt;em&gt;that&lt;/em&gt; much: all I&amp;rsquo;d paid for was ISBN numbers, a couple of fonts, freelance copy-editing, and a business license. But, still, I was in the black now.&lt;/p&gt;

&lt;p&gt;I replied to as many people as I could and then headed into the office to &lt;strike&gt;get some work done&lt;/strike&gt; spend the rest of the day refreshing my browser. Aggregate sales stats started showing up in the various dashboards:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/kindle-hockey.png&quot;&gt;
  &lt;figcaption&gt;Kindle sales on the first day.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/smash-hockey.png&quot;&gt;
  &lt;figcaption&gt;Smashwords (EPUB) sales on the first day.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;CreateSpace doesn&amp;rsquo;t draw a pretty picture for you, but the raw numbers were doing the same thing. I told my coworkers and they got all excited for me.&lt;/p&gt;

&lt;p&gt;The rest of the day was basically a blur of responding to people and telling my wife and team how high the numbers were going. At some point, when I refreshed the Amazon page, I noticed a little banner had appeared next to my book:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/banner.png&quot;&gt;
  &lt;figcaption&gt;No way.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It turns out Amazon tracks book sales &lt;em&gt;very quickly.&lt;/em&gt; For the brief period of time where I had saturated social media, enough sales were coming in to actually make it the best-selling game programming book for a little while.&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/best-game.png&quot;&gt;
  &lt;figcaption&gt;Sorry &amp;ldquo;Learning Python&amp;rdquo;.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Wait, did I say &amp;ldquo;game programming&amp;rdquo;? I meant #1 out of &lt;em&gt;all programming books&lt;/em&gt;:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/best-programming.png&quot;&gt;
  &lt;figcaption&gt;I did a victory lap at this point.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;At it&amp;rsquo;s peak, my book was the #7 best-selling book in the entire computer category:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/best-computer.png&quot;&gt;
  &lt;figcaption&gt;Up there with Minecraft!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Around this time, I started referring to myself in the third person as &amp;ldquo;best-selling author Robert Nystrom&amp;rdquo;. Of course, most of the other books in those lists had been there for weeks or months, but I had my moment in the sun and I was committed to making the most of it.&lt;/p&gt;

&lt;h2&gt;Return to Normalcy&lt;/h2&gt;

&lt;p&gt;The peak, naturally, only lasted about a day. I was most curious to see what the right side of the graph would look like. Would it fall to zero? A slow trickle? A steady passive income?&lt;/p&gt;

&lt;p&gt;When I sent out the email for the book, one thing I asked was for people to write honest, detailed reviews. I figured a book page with a good set of reviews would give it the air of legimitacy for future customers who stumbled onto the book on their own. That in turn would help the book have a longer sales tail.&lt;/p&gt;

&lt;p&gt;Because people are awesome and I love every one of them, people did indeed do this. It took a while, but reviews started trickling in.&lt;/p&gt;

&lt;p&gt;Other pleasant surprises started happening too. The book finally made its way through the other channels. I put it up on &lt;a href=&quot;https://play.google.com/store/books/details/Robert_Nystrom_Game_Programming_Patterns?id=9fIwBQAAQBAJ&quot;&gt;Google Play&lt;/a&gt;, and Smashwords got it onto &lt;a href=&quot;http://itunes.apple.com/us/book/isbn9780990582915&quot;&gt;iBooks&lt;/a&gt;, &lt;a href=&quot;http://www.barnesandnoble.com/w/game-programming-patterns-robert-nystrom/1102794265?ean=2940046391428&quot;&gt;Nook&lt;/a&gt;, and some other places. I finally figured out a place to &lt;a href=&quot;https://payhip.com/b/iZRI&quot;&gt;sell the PDF&lt;/a&gt;. (If you go to &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;the book&amp;rsquo;s site&lt;/a&gt; now, these are all listed there.)&lt;/p&gt;

&lt;p&gt;In a mistake that I don&amp;rsquo;t understand but can&amp;rsquo;t bear to correct, Apple even decided to spice up my name a bit:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/umlaut.png&quot;&gt;
  &lt;figcaption&gt;Robert Nyström, now 15% more metal.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then, a few days later, the most magical part of this whole thing started happening (though, honestly, the umlaut is a close second). That&amp;rsquo;s about how long it took for print copies to get shipped to people.&lt;/p&gt;

&lt;p&gt;Soon, friends and family&amp;mdash;some who I haven&amp;rsquo;t seen in years&amp;mdash;started sending me pictures of their copies of the book. Kind strangers in countries I couldn&amp;rsquo;t find on a map tweeted pictures of themselves opening the shipping box with excitement to see my dumb face staring out at them.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s hard to articulate how profoundly gratifying that is. Through almost the entire six years I&amp;rsquo;ve been working on this book, it&amp;rsquo;s been a purely digital thing. While I spend an astonishing amount of my life on the Internet, it still never quite feels &amp;ldquo;real&amp;rdquo; to me.&lt;/p&gt;

&lt;p&gt;Is rearranging some polarization on an SSD really &lt;em&gt;making&lt;/em&gt; something? Is a few words glowing on an LCD actually communicating with a &lt;em&gt;person&lt;/em&gt;, or just some pixelated avatar?&lt;/p&gt;

&lt;p&gt;But seeing photos of real live people holding an actual &lt;em&gt;physical thing&lt;/em&gt; filled with words and illustrations I put together, and seeing them &lt;em&gt;happy&lt;/em&gt; to have it in their hands finally made it click for me that I made something real that actually affected people.&lt;/p&gt;

&lt;h2&gt;How We&amp;rsquo;re Looking Now&lt;/h2&gt;

&lt;p&gt;Things have mostly settled down since then, though I do still have lots of email to catch up on (sorry!). Now that the book is in pretty much every sales channel, eBook walled garden, and international site for Amazon, I&amp;rsquo;m &lt;em&gt;finally&lt;/em&gt; getting to the point where I can think of the book as &lt;em&gt;done&lt;/em&gt; and put it into the background of my life.&lt;/p&gt;

&lt;p&gt;So far, buyers have been trickling in at a decent rate. Here&amp;rsquo;s what my Kindle sales look like as of writing this post:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/kindle-now.png&quot;&gt;
  &lt;figcaption&gt;EPUB is similar, and I think print is too.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The book has been out about two weeks, and I&amp;rsquo;ve sold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;796 print copies.&lt;/strong&gt; 555 in the US, 145 in Great Britain, 95 in Europe, and 1 directly from createspace.com&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;274 Kindle copies.&lt;/strong&gt; I&amp;rsquo;ll spare you the per country break-down, but it is really cool to see that I&amp;rsquo;ve sold it in India, Japan, Brazil, and other places.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;70 copies from smashwords.&lt;/strong&gt; This is people who wany to buy the EPUB file directly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;7 copies from iBooks.&lt;/strong&gt; The book only appeared a few days ago, so I expect this to catch up with the other channels over time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That&amp;rsquo;s a grand total of &lt;strong&gt;1,147 copies sold in the first two weeks.&lt;/strong&gt; I won&amp;rsquo;t be retiring off of this, but I&amp;rsquo;m really really happy with that number, and unbelievably grateful to everyone who bought a copy.&lt;/p&gt;

&lt;p&gt;While I&amp;rsquo;m planning to take a good long break from serious projects first, this level of success has certainly gotten me pumped about writing another book. If I do, I&amp;rsquo;m 100% confident now in my approach of putting the entire book online for free. I&amp;rsquo;m certain I wouldn&amp;rsquo;t have sold anywhere near this many copies if the book&amp;rsquo;s web site hadn&amp;rsquo;t built an audience who were ready and eager to get their hands on a copy.&lt;/p&gt;

&lt;p&gt;It turns out giving something away is a great way to get something back.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2014/11/03/bringing-my-web-book-to-print-and-ebook</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2014/11/03/bringing-my-web-book-to-print-and-ebook"/>
    <title>Zero to 353 Pages: Bringing My Web Book to Print and eBook</title>
    <published>2014-11-03T00:00:00-08:00</published>
    <updated>2014-11-03T00:00:00-08:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;figure&gt;
  &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;&lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/book.jpg&quot;&gt;&lt;/a&gt;
  &lt;figcaption&gt;Look what I made!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s a funny feeling to spend nearly six years making something and then finally hold it in your hand. It&amp;rsquo;s simultaneously, &amp;ldquo;This is &lt;em&gt;it!&lt;/em&gt;&amp;rdquo; and &amp;ldquo;Is &lt;em&gt;this&lt;/em&gt; it?&amp;rdquo; How can it be so small when it feels like such a big piece of my life?&lt;/p&gt;

&lt;p&gt;Most of that time, &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;the book&lt;/a&gt; existed entirely on the web. It was less &amp;ldquo;book&amp;rdquo; and more &amp;ldquo;book-length manuscript that you can read with your browser&amp;rdquo;. The web site is still the book&amp;rsquo;s real home in some ways. If you want to know more about game programming and software architecture, &lt;a href=&quot;http://gameprogrammingpatterns.com/contents.html&quot;&gt;take a look&lt;/a&gt;. You can read the whole thing online, for free, because I love you.&lt;/p&gt;

&lt;p&gt;I already wrote &lt;a href=&quot;/2014/04/22/zero-to-95688-how-i-wrote-game-programming-patterns/&quot;&gt;a post&lt;/a&gt; about the &lt;em&gt;writing&lt;/em&gt; part of the process. That was the real mountain to climb. But, once I reached the summit and decided (1) I wanted to also have print and eBook editions and (2) I wanted to do it all myself, I learned that one does not simply walk &lt;em&gt;out&lt;/em&gt; of Mordor either.&lt;/p&gt;

&lt;p&gt;This gratuitously, vaingloriously long post is about climbing back &lt;em&gt;down&lt;/em&gt; the mountain&amp;mdash;all of the &lt;em&gt;stuff&lt;/em&gt; required to turn a web site into a book. Remember on Mr. Rogers Neighborhood where they would take a trip to a factory to see how cute little piglets are turned into hotdogs or something charming like that? This is like that, but marginally less incarnadine.&lt;/p&gt;

&lt;h2&gt;Where it Starts&lt;/h2&gt;

&lt;p&gt;On April 22nd, I finished the third draft of the last chapter of the book. The next day, I uploaded it and modestly told a few friends. And by that, I mean I &lt;a href=&quot;https://twitter.com/munificentbob/status/458811197966409728&quot;&gt;milked it&lt;/a&gt; for &lt;a href=&quot;https://plus.google.com/100798142896685420545/posts/HJ3J368V6Mp&quot;&gt;all it was worth&lt;/a&gt; on all &lt;a href=&quot;http://www.reddit.com/r/programming/comments/23qnnc/i_finished_writing_my_free_book_on_game/&quot;&gt;the social networks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As soon as I shook out &lt;a href=&quot;https://github.com/munificent/game-programming-patterns/issues?q=is%3Aissue+is%3Aclosed&quot;&gt;all of the bugs readers reported&lt;/a&gt;, I went straight into working on the print and eBook versions. Like I mentioned in the last post, I work on the book every single day. Not breaking the chain has somehow been just enough of a mindtrick to get me to overcome my usual inability to finish anything bigger than breakfast.&lt;/p&gt;

&lt;p&gt;By this point, I was actually superstitious about breaking it. I really wanted to hold the physical book in my hands, so until that was done, I was afraid to take even single day&amp;rsquo;s break.&lt;/p&gt;

&lt;figure&gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/sb7uzrKnAGA&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
  &lt;figcaption&gt;I did break the chain on &lt;em&gt;one&lt;/em&gt; day. It was my birthday in Kauai. I spent the morning playing on the beach with my kids, the afternoon snorkeling with sea turtles, the evening grilling burgers for my friends, and the night boozing it up. The book kinda slipped my mind.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The first step was doing yet another editing pass over the manuscript. At this point, I&amp;rsquo;d done three drafts of each chapter, but ink on paper is a lot harder to fix than a web site, so I wanted to give it one more round of scrutiny.&lt;/p&gt;

&lt;p&gt;This was also, strangely, the first time I&amp;rsquo;d read the book &lt;em&gt;front to back&lt;/em&gt;. The chapters are relatively unconnected, sort of like recipes in a cookbook, and I wrote them out of order. Everytime I finished a chapter, the next one I started was the one that seemed like the most fun right then.&lt;/p&gt;

&lt;p&gt;I found a bunch of places where I said the same thing twice near each other in the book, but years apart in my life when I wrote them. I fixed those, and tons of other style and tone issues. Then I found a freelance copy editor and got her to do a pass over it.&lt;/p&gt;

&lt;p&gt;Despite having done four drafts at this point, she still found dozens of mistakes that I managed to miss. If you ever write book, I &lt;em&gt;highly&lt;/em&gt; recommend this step. You&amp;rsquo;ll be astonished at how much you miss that a good editor will find.&lt;/p&gt;

&lt;h2&gt;eBooks, Ugh&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m going to mix up the chronology here and talk about the eBook version first. In reality, I interleaved working on this and the print version and going back and forth over chapters with my copy editor, Lauren. The eBook stuff is less exciting than the print design, so let&amp;rsquo;s just get it out of the way.&lt;/p&gt;

&lt;p&gt;I was actually in pretty good shape going in to this. I wrote the book &lt;a href=&quot;https://github.com/munificent/game-programming-patterns/tree/master/book&quot;&gt;in markdown&lt;/a&gt;, and had &lt;a href=&quot;https://github.com/munificent/game-programming-patterns/blob/master/script/format.py&quot;&gt;a little Python script&lt;/a&gt; that takes those files, some CSS, and an HTML template, and burps out the web site.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;ve never done an eBook before (you lucky devil, you), they come in two predominant flavors: EPUB and MOBI. Most of the world uses EPUB, but Kindle demands MOBI in some sort of gigantic distributed prank on the entire writing community.&lt;/p&gt;

&lt;p&gt;An EPUB file is basically a zip file containing a web site. Seriously. Take your static site and run this on it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; my_awesome_site
zip -X0 my_awesome_site.epub mimetype
zip -Xur9D my_awesome_site.epub *
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you&amp;rsquo;re 90% of the way to having an eBook. It&amp;rsquo;s the other 10% that makes you want to claw your eyes out. See, eBooks are a lot like web sites&amp;hellip; circa 2004. Instead of this fancy HTML5 stuff which is clearly, like, living in the future with all of its new tags that don&amp;rsquo;t need to be closed, EPUB requires XHTML, the evil mutant offspring of HTML and XML. The turducken of the markup world.&lt;/p&gt;

&lt;p&gt;Worse, eBook readers handle CSS about as well as Netscape Navigator and IE4 did. If you lived through the horror show that was web design in the &amp;lsquo;90s where you had three browsers open all day, you know what I&amp;rsquo;m talking about. Except that now each of those &amp;ldquo;browsers&amp;rdquo; is a separate physical device that you have to jump through hoops to get your &amp;ldquo;site&amp;rdquo; on.&lt;/p&gt;

&lt;p&gt;Getting an updated &lt;code&gt;.mobi&lt;/code&gt; file into the Kindle app on my tablet involved some combination of Dropbox, an Android file manager, going to the Amazon website to delete the previous version, sending an email to a mysterious dead drop address granted me by Amazon, waiting for the Kindle app to crash a few times, and, on occasion, blood sacrifice.&lt;/p&gt;

&lt;p&gt;The things I do for love.&lt;/p&gt;

&lt;p&gt;Oh, and did I mention the XML? SO MUCH XML. The &lt;a href=&quot;http://idpf.org/epub&quot;&gt;EPUB format&lt;/a&gt; was clearly written by uptight pencil-pushers whose OCD was permanently triggered by the chaos of the web. You need a &lt;code&gt;content.opf&lt;/code&gt; XML manifest that lists &lt;em&gt;every single file&lt;/em&gt; in your eBook. You also need a &lt;code&gt;container.xml&lt;/code&gt; manifest that points to that &lt;code&gt;.opf&lt;/code&gt; file. You need a manifest for your manifest.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.opf&lt;/code&gt; file needs a &lt;code&gt;&amp;lt;spine&amp;gt;&lt;/code&gt; tag containing the ordered list of stuff in the book. And a &lt;code&gt;&amp;lt;guide&amp;gt;&lt;/code&gt; containing&amp;hellip; an ordered list of the stuff in the book. Also, there&amp;rsquo;s a separate&amp;mdash;mandatory, of course!&amp;mdash;&lt;code&gt;toc.nxc&lt;/code&gt; file containing, you guessed it, an ordered list of the stuff in the book. Not only that, each item in the TOC is not just in order but &lt;em&gt;explicitly manually numbered&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;navPoint&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;playOrder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;navLabel&amp;gt;&amp;lt;text&amp;gt;&lt;/span&gt;Copyright&lt;span class=&quot;nt&quot;&gt;&amp;lt;/text&amp;gt;&amp;lt;/navLabel&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;content&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;copyright.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/navPoint&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;navPoint&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;acknowledgements&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;playOrder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;navLabel&amp;gt;&amp;lt;text&amp;gt;&lt;/span&gt;Acknowledgements&lt;span class=&quot;nt&quot;&gt;&amp;lt;/text&amp;gt;&amp;lt;/navLabel&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;content&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;acknowledgements.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/navPoint&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;navPoint&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;dedication&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;playOrder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;3&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;navLabel&amp;gt;&amp;lt;text&amp;gt;&lt;/span&gt;Dedication&lt;span class=&quot;nt&quot;&gt;&amp;lt;/text&amp;gt;&amp;lt;/navLabel&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;content&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;dedication.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/navPoint&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See those little &lt;code&gt;playOrder&lt;/code&gt; attributes? It&amp;rsquo;s like double-entry bookkeeping, minus the fun and excitement of double-entry bookkeeping.&lt;/p&gt;

&lt;p&gt;But, despite my ranting here, it&amp;rsquo;s not really &lt;em&gt;hard&lt;/em&gt;. It&amp;rsquo;s sort of like counting to a thousand by hitting &lt;code&gt;+&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; over and over on your calculator. (I had a fun childhood.) Once you&amp;rsquo;ve got a happy little EPUB file, you throw it at KindleGen, a rancorous old app from Amazon, and it begrudgingly converts it to a MOBI for you. Behold:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/ebooks.png&quot;&gt;
  &lt;figcaption&gt;It took me almost six years to make these two files.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If you ignore the fact that it took about a hundred iterations to please the &lt;a href=&quot;http://validator.idpf.org/&quot;&gt;EPUB validator&lt;/a&gt; Gods, this was straightforward. Now, let&amp;rsquo;s talk about the fun stuff!&lt;/p&gt;

&lt;h2&gt;My Dirty Little Secret&lt;/h2&gt;

&lt;p&gt;Warning: Seriously ardent exposition on design lies ahead. The rest of this post will be like watching two of your best friends who after years of awkward sexual tension finally hook up and now aren&amp;rsquo;t so much showering you with public displays of affection as they are public displays of not-always-entirely-dry humping. I really &lt;em&gt;really&lt;/em&gt; like fonts.&lt;/p&gt;

&lt;p&gt;When I first started the book, I wrote a little promise to myself in my pink locked diary that I never show anyone. (Except now you, I guess, Dearest Reader.) That promise was, &amp;ldquo;If I can finish writing this whole damn manuscript, I will let myself typeset it.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;I know that probably sounds strange but if you haven&amp;rsquo;t figured out I&amp;rsquo;m a bit off center by now, you must be skimming this post for the pictures.&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/pumpkin.jpg&quot;&gt;
  &lt;figcaption&gt;Here&amp;rsquo;s one of a tiny pumpkin pie I baked!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Most of my life, I had one cranial hemisphere in the artist bucket and one in the logical bin. I grew up drawing and painting, but usually on graph paper.&lt;/p&gt;

&lt;p&gt;A quick trip down my résumé makes stops at computer animator, web designer, UI designer, part-time UI programmer, &lt;em&gt;full&lt;/em&gt;-time UI programmer, and tools programmer, before finally landing on regular full-on programmer. My left brain metastasized and took over pretty much the whole light show upstairs.&lt;/p&gt;

&lt;p&gt;I love programming, and I&amp;rsquo;m happy to spend almost all day doing stuff that&amp;rsquo;s not that visual, but, man, sometimes I really miss design. Thus the vow: if I could complete this giant ball of logical thought, I would reward myself by fully giving into my artistic side.&lt;/p&gt;

&lt;h2&gt;You Mean I Get To Pick a Page Size?&lt;/h2&gt;

&lt;p&gt;Of the design stuff I &lt;em&gt;have&lt;/em&gt; done in the past, almost all of it has been for the web. There&amp;rsquo;s a lot to like about web design, but it&amp;rsquo;s sort of like body painting. No matter how steady you are with your airbrush, there&amp;rsquo;s an inherit squishiness and unreliability to the underlying medium.&lt;/p&gt;

&lt;p&gt;When you can&amp;rsquo;t trust the user not to futz with the size of their browser window or even control what fonts they have access to, it&amp;rsquo;s hard to design something that looks exactly the way you want. But, &lt;em&gt;print&lt;/em&gt;, now that&amp;rsquo;s a different story.&lt;/p&gt;

&lt;p&gt;The first thing I did was decide how big the pages would be. Let me repeat that for you web folks: &lt;strong&gt;I, the designer, got to &lt;em&gt;choose&lt;/em&gt; the page size.&lt;/strong&gt; Because Amazon is the giant gorilla of the publishing industry and &lt;a href=&quot;https://www.createspace.com/&quot;&gt;CreateSpace&lt;/a&gt; is its cuddly orangutan buddy, I decided to go with that for handling the print-on-demand production of the book. They have a &lt;a href=&quot;https://www.createspace.com/Special/Pop/book_trimsizes-pagecount.html&quot;&gt;few different trim sizes&lt;/a&gt; you can pick from.&lt;/p&gt;

&lt;p&gt;I grabbed a bunch of programming books I had nearby, took my ruler out, and measured those suckers. I wanted my book to be like a real programming book, so I measured their dimensions, margins, line height, font size, the works. I took some averages, settled on 7.5&amp;quot; &amp;times; 9.25&amp;quot; and that was that.&lt;/p&gt;

&lt;h2&gt;Fonts, Fonts, Fonts&lt;/h2&gt;

&lt;p&gt;Now that I knew how big my canvas was, it was time to start painting it. And, for a book, that means fonts. Sweet, delicious, heavenly fonts.&lt;/p&gt;

&lt;p&gt;As a web designer, I was used to&amp;mdash;paraphrasing Henry Ford here&amp;mdash;having any serif I wanted, as long as it was Georgia. (And I remember the days &lt;em&gt;before&lt;/em&gt; Georgia, a ghastly fever dream thankfully cured by heroic doctor &lt;a href=&quot;http://en.wikipedia.org/wiki/Matthew_Carter&quot;&gt;Matthew Carter&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.google.com/fonts&quot;&gt;Google Web Fonts&lt;/a&gt; turned things up a notch, but once you filter out all of the fonts on there that &lt;a href=&quot;https://www.google.com/fonts/specimen/Domine&quot;&gt;don&amp;rsquo;t have italics&lt;/a&gt;, or &lt;a href=&quot;https://www.google.com/fonts/specimen/Vollkorn&quot;&gt;have shitty metrics&lt;/a&gt;, or incomplete character sets, or &lt;a href=&quot;https://www.google.com/fonts/specimen/EB+Garamond&quot;&gt;only one weight&lt;/a&gt;, what you&amp;rsquo;re left with is&amp;hellip; well, Georgia starts looking pretty good again.&lt;/p&gt;

&lt;p&gt;But, now. Now! I could just &lt;em&gt;go out and buy a fucking font and then use it&lt;/em&gt;. Any font I wanted! It was intoxicating. Incredible. Overwhelming. Paralyzing.&lt;/p&gt;

&lt;p&gt;I spent nights in a hallucinogenic daze going through dozens of serif (for body copy), sans serif (asides and headers), and monospace (code, naturally) fonts. For all I know, it could have been weeks. Time had lost all meaning. When my fugue dissipated, I had a beard, a Grateful Dead tattoo, and three fonts.&lt;/p&gt;

&lt;p&gt;Ironically, the first two, Source Sans Pro and Source Code Pro, &lt;em&gt;are&lt;/em&gt; Google Web Fonts, and are what &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;the site&lt;/a&gt; uses:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/source.png&quot;&gt;
  &lt;figcaption&gt;Not pictured: beard and tattoo.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I don&amp;rsquo;t know if this is astute branding on my part or just a failure of imagination, but do I think Adobe really nailed it with Source Code Pro&amp;mdash;even when in print&amp;mdash;and it pairs just as perfectly with Source Sans as theirs names would lead you to believe.&lt;/p&gt;

&lt;p&gt;That just left a body font, the most important font in the book. Like I do, I over-constrained the hell out of the problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I wanted a relatively small &lt;a href=&quot;http://www.typographydeconstructed.com/x-height/&quot;&gt;x-height&lt;/a&gt;.&lt;/strong&gt; I don&amp;rsquo;t dig the current trend of really big x-heights, especially not in print. They look like a schoolgirl&amp;rsquo;s loopy handwriting to me, minus hearts over the &amp;ldquo;i&amp;quot;s. If I&amp;rsquo;m going to print this bad boy at 2400 DPI, it can handle some nice small &lt;a href=&quot;http://www.typographydeconstructed.com/bowl/&quot;&gt;bowls&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But not &lt;em&gt;too&lt;/em&gt; small.&lt;/strong&gt; The prose is heavily seasoned with &lt;code&gt;inline code&lt;/code&gt;, so the body and code fonts need to have similar vertical metrics or it will look like Danny DeVito and Arnold Schwarzenegger in &lt;em&gt;Twins&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I love &lt;a href=&quot;http://www.fonts.com/content/learning/fontology/level-1/type-families/oldstyle&quot;&gt;Old Style&lt;/a&gt; typefaces.&lt;/strong&gt; Garamond, Jenson, and Bembo are my homeboys. Low contrast in line thickness, angled stress and a bit of humanist irregularity, &lt;em&gt;aww yiss.&lt;/em&gt; I can&amp;rsquo;t stand the wimpy horizontal strokes of Didone fonts. I seriously get irrationally angered by them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But a font that&amp;rsquo;s &lt;em&gt;too&lt;/em&gt; calligraphic would clash with the other fonts.&lt;/strong&gt; A page should look like a cohesive whole. That won&amp;rsquo;t happen if the body text looks enscribed by a medieval monk&amp;rsquo;s quill pen while the code and headers are machined out by a robot.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you distill that down, what I really wanted was a font with the &lt;em&gt;metrics&lt;/em&gt; of an Old Style, but the &lt;em&gt;letterforms&lt;/em&gt; of a cleaner modern typeface. Also, it needed a heavier weight and a spritely italic. I swear, italics trigger some kind of delectable synaesthetic response in me like the electric tingle of a battery on my bathing suit area.&lt;/p&gt;

&lt;p&gt;After days of poring over typography blogs and font sites, lo and behold, I found a match. My Manic Pixie Dreamgirl in OpenType Format. &lt;em&gt;Sina Nova.&lt;/em&gt;&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/sina.png&quot;&gt;
  &lt;figcaption&gt;Sorry for the linguistic liberties, Vlad. I&amp;rsquo;m sure you understand.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;God, just look at it there. And wait until you see the &lt;em&gt;ligatures&lt;/em&gt;. It&amp;rsquo;s enough to make a girl swoon.&lt;/p&gt;

&lt;p&gt;I had assembled my army, now it was time to draw battlelines.&lt;/p&gt;

&lt;h2&gt;So Many Grids&lt;/h2&gt;

&lt;p&gt;Some people fantasize about building &lt;a href=&quot;https://www.youtube.com/watch?v=PGRgXWsL-_Y&quot;&gt;roller coasters in their backyards&lt;/a&gt; or &lt;a href=&quot;https://www.youtube.com/watch?v=OmX1V6_gukY&quot;&gt;being smothered in pugs&lt;/a&gt;. I&amp;rsquo;ve always dreamt of designing using an honest-to-God &lt;a href=&quot;http://www.amazon.com/Systems-Graphic-Systeme-Visuele-Gestaltung/dp/3721201450&quot;&gt;grid system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve tried to approximate them for the web but it always ends up leaving me disappointed and slightly ashamed like trying to use role-play to reinvigorate a relationship you both know is dead. Not this time, though. I had a brand new copy of InDesign, and I wasn&amp;rsquo;t afraid to use it!&lt;/p&gt;

&lt;p&gt;For those who don&amp;rsquo;t know, a grid system organizes the content on a page. You come up with the dimensions of an invisible grid that overlays the page and everything slots within those. When done well, the text hangs together in placid harmony like a zen garden.&lt;/p&gt;

&lt;p&gt;Coming up with a good grid, especially for this book, was quite hard. Again, I had a bunch of constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Of course, it has to take into account the page size, and the margins. Wider margins on the inside so you don&amp;rsquo;t get to close to the spine. We&amp;rsquo;re an actual book now!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you&amp;rsquo;ve &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;read any of the book&lt;/a&gt;, you know it&amp;rsquo;s full of asides that provide commentary and additional info. The &lt;a href=&quot;http://gameprogrammingpatterns.com/singleton.html#to-limit-a-class-to-a-single-instance&quot;&gt;longest one&lt;/a&gt; is a few paragraphs and they often need to appear right next to certain passages of text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Of course, being a programming book, we&amp;rsquo;ve got lots of code samples. Those need to be fairly wide so you don&amp;rsquo;t have to wrap the lines very much.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code is particularly tricky. I like a pretty large line height (think single- versus double-spaced) for prose, but code looks wrong if you spread it out that much. Most grids use a single line height for the vertical rhythm of the page, but that wouldn&amp;rsquo;t work for both prose and code (or for the asides for that matter).&lt;/p&gt;

&lt;p&gt;After days of tinkering&amp;mdash;wonderful, relaxing, theraputic, tinkering&amp;mdash;I had something I liked. To get there, I picked a random chapter and mocked it up. You can&amp;rsquo;t design a layout without something to lay out, and I believe the design should take into account the actual content, so no &lt;em&gt;lorem ipsum&lt;/em&gt; for me. I ended up with this:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/grid.png&quot;&gt;
  &lt;figcaption&gt;Mmm.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Three 2&amp;rdquo; columns with a &amp;frac14;&amp;ldquo; gutter, two for the main text and one for the asides. I used the same spacing vertically for large elements like headers on chapter title pages.&lt;/p&gt;

&lt;p&gt;For the main vertical rhythm, I came up with a fractional line height. The core baseline was 4.5&amp;thinsp;pt. Prose fell on every third line, and code and aside every second. That let the latter snuggle in a little tighter while still having some semblance of a vertical cadence across the entire page:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/lines.png&quot;&gt;
  &lt;figcaption&gt;9&amp;thinsp;pt for code and asides, 13.5&amp;thinsp;pt for prose.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I set up a running footer, and designed the section and chapter headers. Not gonna lie: I was pretty pleased with myself. There may have been some celebratory drinking.&lt;/p&gt;

&lt;h2&gt;Oh no, XML Again?&lt;/h2&gt;

&lt;p&gt;Once I had my grid and fonts, all that was left to do was typeset the whole book. That meant bringing in all of the text. I couldn&amp;rsquo;t just copy and paste the web pages into InDesign. I&amp;rsquo;d already carefully authored (in markdown) emphasis, bold, lists, headers, subheaders, etc. I did &lt;em&gt;not&lt;/em&gt; want to start from plaintext and do that all over again.&lt;/p&gt;

&lt;p&gt;Fortunately, InDesign has a feature called &amp;quot;XML import&amp;rdquo;. You can take an arbitrary XML document, import it to InDesign, and automatically map XML tags to paragraphic and character styles you&amp;rsquo;ve created in InDesign. Unfortunately, this feature seems to have been implemented by a narcoleptic intern who sidestepped any code review process.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s one of the buggiest pieces of nominally commercial-grade software I&amp;rsquo;ve ever used. I, on more than one occasion, managed to get it to completely corrupt an InDesign file beyond repair. (Fortunately, help was just a &lt;code&gt;git reset&lt;/code&gt; away.)&lt;/p&gt;

&lt;p&gt;I cracked open my little Python script and hacked it up to convert the markdown to HTML and then, through an unholy series of regexes, mash that into something approximating XML. Stuff like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;clean_up_code_xml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Ditch most code formatting tags.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;span class=&amp;quot;(k|kt|mi|n|nb|nc|nf)&amp;quot;&amp;gt;([^&amp;lt;]+)&amp;lt;/span&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;\2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Turn comments into something InDesign can map to a style.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;span class=&amp;quot;(c1|cn)&amp;quot;&amp;gt;([^&amp;lt;]+)&amp;lt;/span&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;comment&amp;gt;\2&amp;lt;/comment&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;clean_up_xhtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Ditch newlines in the middle of blocks of text. Out of sheer malice,&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# even though they are meaningless in actual XML, InDesign treats them&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# as significant.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;\n(?&amp;lt;!&amp;lt;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Also collapse redundant whitespace.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot; +&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;gt; &amp;lt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;gt;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Re-add newlines after closing paragraph-level tags.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/h2&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/h3&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/h3&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/ol&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/pre&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/aside&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/aside&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/blockquote&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Forgive me Father, for I have sinned. In my defense, I wasn&amp;rsquo;t writing a program to convert &lt;em&gt;any&lt;/em&gt; HTML to XML. As long as it worked on the 90k words of &lt;em&gt;my&lt;/em&gt; book, it was Correct&amp;trade; as far as I&amp;rsquo;m concerned. This gave me a folder full of more-or-less XML files, one for each chapter. All that was left was to typeset them.&lt;/p&gt;

&lt;h2&gt;I&amp;rsquo;m a Designer!&lt;/h2&gt;

&lt;p&gt;Starting at chapter one, &lt;a href=&quot;http://gameprogrammingpatterns.com/introduction.html&quot;&gt;the introduction&lt;/a&gt;, I imported its XML into InDesign. Then the work started. Each aside had to be pulled out of the main body text, restyled, and put into the sidebar. I only wanted leading indentation on paragraphs that followed previous ones, so every &amp;ldquo;first&amp;rdquo; paragraph that followed a header or code sample needed to be styled. I could never get lists to work in the XML, so I restyled all of those manually.&lt;/p&gt;

&lt;p&gt;Then the real work started. I redid every illustration to look sharp in a black-and-white, high resolution medium. I brought all sixty-something of them into Photoshop, removed the graph lines, upscaled the hell out of them, did some shenanigans to smooth the edges (but not &lt;em&gt;too&lt;/em&gt; smooth since that&amp;rsquo;s part of their charm) and then saved them as 2400 DPI TIFFs:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/illustration.png&quot;&gt;
  &lt;figcaption&gt;Original web version on the left, upscaled and monochrome print version the right.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then the real, hard work started. You see, all of that is just grunt work. You could probably get it done on Mechanical Turk if you wanted to, or just &lt;a href=&quot;https://www.tug.org/TUGboat/tb21-3/tb68fine.pdf&quot;&gt;let Knuth solve it&lt;/a&gt; with some clever dynamic programming. Where the &lt;em&gt;art&lt;/em&gt; comes into play is dealing with this one little problem: &lt;em&gt;where do you put the page breaks?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First off, you want to minimize &lt;a href=&quot;http://en.wikipedia.org/wiki/Widows_and_orphans&quot;&gt;widows and orphans&lt;/a&gt;&amp;mdash;things like when the last line of a paragraph is at the top of the next page. InDesign can automate this, and even handle more complex rules like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keep headers with at least a line or two of the paragraph that follows them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don&amp;rsquo;t let a block of code be split across pages at all.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a code block follows a paragraph of body copy, keep at least the last line of the body text with the code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This stuff is why people get all excited about InDesign. It rocks.&lt;/p&gt;

&lt;p&gt;But, once I set up all of those rules, I discovered I&amp;rsquo;d basically turned InDesign into HAL 9000. Except, instead of refusing to open the pod bay doors, what it was forced to do was break a lot of things really &lt;em&gt;early&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You see, once I set up all of these rules, the result was that big chunks of text&amp;mdash;headers, body text, and code&amp;mdash;were all inseparably glued to each other. Since I told InDesign not to split in the middle, the only thing it could do was move the whole kit and caboodle to the next page, leaving a huge blank area at the bottom of the previous page, like:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/space.png&quot;&gt;
  &lt;figcaption&gt;Most of the left (verso) page is wasted space.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There&amp;rsquo;s no magic bullet to fix this. I just took it a page at a time and tried to organize and distribute the whitespace as nicely as I could. Usually, I could fill in a gap in one page by pushing a bit of stuff from earlier pages down. Other times, I&amp;rsquo;d tweak the code to shave off a line or two, just enough to get it to fit. On occasion, I&amp;rsquo;d break code samples into separate pieces so it could span pages.&lt;/p&gt;

&lt;p&gt;See for yourself:&lt;/p&gt;

&lt;figure&gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/4_4Uw_9ZMIs&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
  &lt;figcaption&gt;Now imagine this playing back 24 times slower.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It was tedious, challenging work. I started on June 19th. Working every single day, I reached the end of the last chapter &lt;a href=&quot;https://github.com/munificent/game-programming-patterns/blob/60a4f3ebf49d7c24aa8ffc3100d48d0e2486039f/note/log.txt#L39-L92&quot;&gt;exactly two months later&lt;/a&gt;. There was more drinking.&lt;/p&gt;

&lt;h2&gt;Baby Got Back (Matter)&lt;/h2&gt;

&lt;p&gt;So, the print edition was done, right? Nope! Real books aren&amp;rsquo;t just a pile of chapters. They&amp;rsquo;ve got a copyright page, title page, table of contents, and all sorts of stuff like that. The bits of those that come before the meat of the book are called &lt;em&gt;front matter&lt;/em&gt; and the rest are, obviously, &lt;em&gt;back matter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I spent a few more days designing a table of contents. (I just had to make it pretty. InDesign handled actually filling it in.) I wrote a copyright page, and &lt;a href=&quot;http://gameprogrammingpatterns.com/acknowledgements.html&quot;&gt;acknowledgements&lt;/a&gt;, even a dedication:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/dedication.jpg&quot;&gt;
  &lt;figcaption&gt;Showing this page to my wife was one of the highlights of this whole adventure.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then I moved onto the back matter. I guess a non-fiction book should have an index, right? Where&amp;rsquo;s the &amp;ldquo;automatically index my whole book button?&amp;rdquo; What&amp;rsquo;s that? There isn&amp;rsquo;t one? Well&amp;hellip; &lt;em&gt;shit&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;InDesign &lt;em&gt;can&lt;/em&gt; create an index for you, bless its little heart, but it doesn&amp;rsquo;t actually know English. You have to sprinkle the index references throughout your book. What it does is figure out what pages those references are on and builds the list of index entries at the end.&lt;/p&gt;

&lt;p&gt;I spent two weeks going over the entire book &lt;em&gt;again&lt;/em&gt;, adding index entries for anything I could imagine someone wanting to look up. I don&amp;rsquo;t promise that it&amp;rsquo;s a great index, but it &lt;em&gt;is&lt;/em&gt; an index, God dammit.&lt;/p&gt;

&lt;p&gt;While I was at it, I cross-referenced the whole book. See, the web version has these magical things called &amp;ldquo;hyperlinks&amp;rdquo;. When one chapter mentions a concept on another one, you can &amp;ldquo;click&amp;rdquo; them with your &amp;ldquo;mouse&amp;rdquo; and the computer takes you straight to the referenced chapter! It&amp;rsquo;s like living in the future but with less Stallone and Wesley Snipes homo-erotically punching each other.&lt;/p&gt;

&lt;p&gt;Paper, alas, does not support web standards. Instead you just put &amp;ldquo;(see page 123)&amp;rdquo; and the reader, poor plebian, has to manually turn to that page theirself. You can create cross references in InDesign and it will automatically track the referenced section and keep the page number up to date. I found every place where there was a link in the web version and manually created a cross-reference.&lt;/p&gt;

&lt;h2&gt;Getting My Grubby Paws On It&lt;/h2&gt;

&lt;p&gt;Phew! Book production is a lot of work! But this was finally nearing the end! I printed the whole book, all three-hundred-plus pages of it on my laser printer. It was heavy! I made a big heavy thing all by myself. Full of words!&lt;/p&gt;

&lt;p&gt;I went to the store and bought a red pen. I proofread every single page. I read my book, on paper. It, finally, after all these years, started to feel like a real thing.&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/pages.jpg&quot;&gt;
  &lt;figcaption&gt;This took a while to print.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I went back and fixed everything that got the red pen treatment, mainly just minor formatting bugs, then I exported a PDF. (Brief interlude where I zoom into 1000% and drool over Sina Nova again.) I uploaded it to CreateSpace. Oh boy oh boy oh boy.&lt;/p&gt;

&lt;p&gt;Oh, crap. I&amp;rsquo;m not done yet. I forgot the cover!&lt;/p&gt;

&lt;h2&gt;Cover Me, I&amp;rsquo;m Going In!&lt;/h2&gt;

&lt;p&gt;If you go by self-publishing blogs, designing a cover is the hardest, most important, most agonized over, most terribly done part of book writing. For every blog post telling you how important it is to not screw it up, there are a hundred self-published books whose cover is some amalgamation of still-watermarked screen-res stock photography, fonts that come pre-installed on Windows 95, and a design aesthetic clearly based on the belief that if one drop shadow is good, ten must be better.&lt;/p&gt;

&lt;p&gt;I didn&amp;rsquo;t want to be that guy.&lt;/p&gt;

&lt;p&gt;To check myself, I spent some time looking at other game programming book covers. I even made a little page of thumbnails so I could put my cover mockups in there to see how they compared:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/thumbnails.jpg&quot;&gt;
  &lt;figcaption&gt;Where&amp;rsquo;s my book hiding in there?&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There&amp;rsquo;s a delicate art to crafting a design that gets the readers attention, but not in that &amp;ldquo;what the hell was he thinking?&amp;rdquo; way.&lt;/p&gt;

&lt;p&gt;The cover I&amp;rsquo;d had in the back of my head for a long time was something hand-drawn. The book is full of little flow-charty illustrations, and I like how their informality contrasts with the technical content of the book.&lt;/p&gt;

&lt;p&gt;After trying a bunch of different mocks for other ideas, I spent an afternoon drawing one big illustration that combined a bunch my favorites from the book.
I took a ton of photos of it at different angles with a macro lens and then tried to find a composition for the text that I liked. You can see the evolution here:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/covers.jpg&quot;&gt;
  &lt;figcaption&gt;In chronological order.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Hopefully, you don&amp;rsquo;t hate the final one too much.&lt;/p&gt;

&lt;h2&gt;My Esteemed Publisher&lt;/h2&gt;

&lt;p&gt;Oh, I left out one piece of the puzzle! Look on the bottom right corner of those mocks. See that? Here, look closer:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/gb.jpg&quot;&gt;
  &lt;figcaption&gt;A little logo.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;To publish a book, you need an &lt;em&gt;ISBN number&lt;/em&gt;. CreateSpace can give you a free one, but then you can&amp;rsquo;t use that anywhere else, and it associates the &amp;ldquo;publisher&amp;rdquo; of that number with CreateSpace, which felt weird to me. I&amp;rsquo;d also need separate ISBN numbers for the two eBook versions.&lt;/p&gt;

&lt;p&gt;ISBNs work a bit like domain names. Each country has an appointed registrar&amp;mdash;the company who is allowed to distribute ISBNs to publishers in one country. In the US, that&amp;rsquo;s &lt;a href=&quot;https://www.myidentifiers.com/&quot;&gt;Bowker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a pretty smart racket. They basically just hand out IDs, a process that could be automated with five lines of Perl code and a copy of Apache running on an Arduino. In return for that, they get to charge you $125 for a single ISBN number. Or you can get 10 for $275. Since everyone publishes both print and eBook versions, you basically always get the 10-pack. They know what they&amp;rsquo;re doing.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s certainly the most money I&amp;rsquo;ve ever paid for 130 digits, but whatever. I sent them my credit card deets and started filling out the form. Whereupon I reached a &lt;em&gt;mandatory&lt;/em&gt; field for &amp;ldquo;publisher&amp;rdquo;. Apparently, &amp;ldquo;Yours Truly&amp;rdquo;, &amp;ldquo;I Just Did It Myself&amp;rdquo;, &amp;ldquo;Fake Vanity Press&amp;rdquo;, and &amp;ldquo;Can&amp;rsquo;t I Just Skip This?&amp;rdquo; are not valid values for that field.&lt;/p&gt;

&lt;p&gt;There was only one thing to do: &lt;em&gt;It&amp;rsquo;s business time.&lt;/em&gt; I got myself a business license. I am a real deal publisher. Look, it says so right here:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/license.jpg&quot;&gt;
  &lt;figcaption&gt;I guess this blog means I&amp;rsquo;ve now posted this conspicuously?&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Now, when I was looking at other game programming books, I saw a bunch of others that were clearly self-published. The dead giveaways were &amp;ldquo;publishers&amp;rdquo; that were either (a) the author&amp;rsquo;s name or an anagram of such, (b) obviously the name of a pet, or &amp;copy; one of the &amp;ldquo;we&amp;rsquo;ll give you an ISBN for free&amp;rdquo; companies.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t think there&amp;rsquo;s anything wrong with self-publishing, obviously, but it does carry a stigma to some readers. I don&amp;rsquo;t want them to see a jokey &amp;ldquo;publisher&amp;rdquo; and think the book is some amateur hour affair. While my writing style is light-hearted, I actually do take the content really seriously.&lt;/p&gt;

&lt;p&gt;Older, established publishers tend to agglomerate over time yielding titles like &amp;ldquo;Harcourt, Brace &amp;amp; Howe&amp;rdquo;, &amp;ldquo;Harcourt Brace Jovanovich&amp;rdquo;, &amp;ldquo;Reed Elsevier&amp;rdquo;, and &amp;ldquo;Houghton Mifflin Riverdeep&amp;rdquo;. So I picked two stuffy-sounding names and stuck them together. Then I debated how to join them&amp;mdash;&amp;ldquo;+&amp;rdquo; (too mathy), &amp;ldquo;|&amp;rdquo; (too &amp;#39;90s), &amp;ldquo;-&amp;rdquo; (hyphen, en-dash, or em-?), and &amp;ldquo;/&amp;rdquo; (too much like a boxing match)&amp;mdash;before finally settling on just a plain space.&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/genever-benning.png&quot;&gt;
  &lt;figcaption&gt;I even drew a logotype, just for kicks.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Although, for the record, I &lt;em&gt;did&lt;/em&gt; still name it after my pets. I just took their names&amp;mdash;Ginny and Benny&amp;mdash;and classed them up. As the CEO and CFO of the Genever Benning empire, they are skilled executives, though a bit prone to farting in board meetings.&lt;/p&gt;

&lt;h2&gt;Upload it, Already!&lt;/h2&gt;

&lt;p&gt;OK, so we&amp;rsquo;ve got typeset chapters, front matter, back matter, a cover, ISBN numbers, a camera-ready PDF. All systems are go go go! I uploaded everything to CreateSpace, waited for their &amp;ldquo;manual&amp;rdquo; review process to complete and ordered a couple of proof copies.&lt;/p&gt;

&lt;p&gt;The next few days were like waiting for Santa and then&amp;hellip; in his traditional brown UPS suit, Santa arrived! The cover looked great! The back cover was even better than I&amp;rsquo;d hoped! (Sorry, you&amp;rsquo;ll have to get your hands on a copy to see it.) The binding looked solid! It looked like a professional quality book! I was super pumped!&lt;/p&gt;

&lt;p&gt;Imagine you muster up the courage to crawl out of your nerd hole and ask the captain of the cheerleading team to go to prom with you. Wonder of wonders, she says &amp;ldquo;yes&amp;rdquo;! That&amp;rsquo;s how I felt.&lt;/p&gt;

&lt;p&gt;With my wife looking over my shoulder, I cracked it open.&lt;/p&gt;

&lt;p&gt;Then imagine you look that cheerleader in the eye and the realization crawls down your spine that her &amp;ldquo;yes&amp;rdquo; was laden with sarcasm you missed the first time around. She would never in a million years go to prom with you.&lt;/p&gt;

&lt;p&gt;Somehow, despite my meticulous measuring and scrupulous adherence to CreateSpace&amp;rsquo;s guidelines, my layout was bad. The text was too small. The top margin too short. Worst of all, the inner margin was too narrow, making it hard to read text near the spine.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Merde.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;OK, Let&amp;rsquo;s Do it All Again&lt;/h2&gt;

&lt;p&gt;As you surely realize by now, changing any of the metrics of the book is a huge undertaking. Sure, you can just edit the master and all of the pages update. But that in turn affects how the text wraps, which then totally undoes all of my careful fitting of blocks of stuff onto different pages. That grueling two-month period where I laid out each page? Out the window now.&lt;/p&gt;

&lt;p&gt;I went back to the drawing board. I cracked open the master. I started re-measuring things. Part of the problem was that (unsurprisingly) I&amp;rsquo;d over-constrained myself. In addition to needing decent margins, a good-sized sidebar, and the right line height, I also wanted measurements that were relatively round numbers. A column width of 1.35728261&amp;quot; is no fun to work with.&lt;/p&gt;

&lt;p&gt;In the process of rounding some of those measurements to the nearest nice round number, I&amp;rsquo;d strayed away from actual good metrics. After bumping up the text size a bit, I spent days trying to come up with a column width, gutter size, and line height that would fit within the page margins and be easy to read.&lt;/p&gt;

&lt;p&gt;Eventually, I found a way out: decimal inches. Most of my print work has used&amp;hellip; shall we say&amp;hellip; imperial measurements? Things like 16pt or 3/16&amp;quot;. In other words, usually some power of two fraction of an inch. But that&amp;rsquo;s not the only option. You can go French revolution and actually do things like 1.3&amp;quot;. InDesign won&amp;rsquo;t bat an eye at it.&lt;/p&gt;

&lt;p&gt;After a bunch of monkeying around, I found a new grid. Instead of a vertical grid where prose is every three grid lines and code is every two, I bumped the fraction to &amp;frac34;. This opened up the code and asides a bit relative to the text. I brought down the top margin and gave myself more than enough breathing room near the spine.&lt;/p&gt;

&lt;p&gt;All that was left to do was update all of the pages. By this point, I was angry and fired up. I was &lt;em&gt;so close&lt;/em&gt; to thinking the book was done and I just wanted it to be over. I &lt;em&gt;burned&lt;/em&gt; through those pages, working on them practically every waking moment. This time, I got the whole three-hundred-something pages done in a week:&lt;/p&gt;

&lt;figure&gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/ikirNuS7jrI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
  &lt;figcaption&gt;Fortunately, years playing Pokemon have given me fantastic grinding skills.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I uploaded a new PDF, crossed my fingers and waited for the new proof to arrive. When it did&amp;hellip; God what a sigh of relief. It looked fine. Totally readable. Hallelujah.&lt;/p&gt;

&lt;p&gt;That readability was great because it made it much easier for me to notice all the dumb mistakes I&amp;rsquo;d made in my hurried re-layout. Somehow, I&amp;rsquo;d managed to break all of the cross references, and sprinkle typos through much of the code. I did &lt;em&gt;another&lt;/em&gt; proof-reading pass on the actual proof:&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/11/postits.jpg&quot;&gt;
  &lt;figcaption&gt;Every note is a mistake.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I fixed those, and uploaded it again. And&amp;hellip; that&amp;rsquo;s it. I know there are still mistakes lurking in there, and thinking about them &lt;em&gt;kills&lt;/em&gt; me. But, at some point, the value of getting the damn thing in people&amp;rsquo;s hands outweighs the value of trying to keep making it better.&lt;/p&gt;

&lt;h2&gt;Kicking it Out the Door&lt;/h2&gt;

&lt;p&gt;The print edition was done, and I made a slew of final changes to the eBook versions&amp;mdash;mainly getting the cover in and working. Finally, only three things were left to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Redo the front page of the site to mention the new formats.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upload everything to the various market places and put them on sale.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write this blog post.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you&amp;rsquo;re reading this, it looks like I got those done too! You can see for youself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;new site&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;a href=&quot;http://www.amazon.com/dp/0990582906&quot;&gt;print version on Amazon&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;a href=&quot;http://www.amazon.com/dp/B00P5URD96&quot;&gt;Kindle version&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;a href=&quot;https://www.smashwords.com/books/view/489921&quot;&gt;eBook at Smashwords&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;iBooks should be coming soon but Apple is busy manually reviewing erotica submissions so it may be a few weeks and I was too impatient to wait for that.&lt;/p&gt;

&lt;p&gt;This whole production ended up taking six months. It was a ton of work, but I don&amp;rsquo;t regret doing it. For better or worse, I can now hold this book and know that it&amp;rsquo;s &lt;em&gt;mine&lt;/em&gt;. From cover to cover, every word, picture, and bit of ink was up to me. I had a ton of help from my copy editor and from every kind reader who sent a bug report or pull request, and the book is immensely better thanks to their input. But, ultimately, the &lt;em&gt;decisions&lt;/em&gt; were all mine.&lt;/p&gt;

&lt;p&gt;What I&amp;rsquo;m feeling now is a curious mixture of relief, gratitude, and trepidation. Relief that it&amp;rsquo;s done and I actually pulled off completing a large project. Immense gratitude to everyone who encouraged me to keep going. I know I wouldn&amp;rsquo;t have finished without that.&lt;/p&gt;

&lt;p&gt;But, finally, trepidation. People&amp;mdash;you&amp;mdash;have been really supportive of the book, which is truly the best feeling in the world. But there&amp;rsquo;s a big difference between &lt;em&gt;saying&lt;/em&gt; you like the book and &lt;em&gt;spending cold hard cash on it&lt;/em&gt;. I&amp;rsquo;ve never written this for the money, but the number of copies it sells will, in some ways, legitimize it in my mind. And that&amp;rsquo;s entirely outside of my control now.&lt;/p&gt;

&lt;p&gt;I feel like I&amp;rsquo;m walking on stage, alone, squinting through the footlights to see if there&amp;rsquo;s anyone in the audience.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2014/07/15/a-turn-based-game-loop</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2014/07/15/a-turn-based-game-loop"/>
    <title>A Turn-Based Game Loop</title>
    <published>2014-07-15T00:00:00-07:00</published>
    <updated>2014-07-15T00:00:00-07:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;style&gt;
canvas {
  padding: 6px;
  background: #222;
  margin: 10px auto;
  max-width: 90%;
  display: block;
}
&lt;/style&gt;

&lt;p&gt;Now that &lt;a href=&quot;http://munificent.github.io/hauberk/&quot;&gt;my roguelike&lt;/a&gt; written in &lt;a href=&quot;http://dartlang.org&quot;&gt;Dart&lt;/a&gt; is &lt;a href=&quot;https://github.com/munificent/hauberk&quot;&gt;open source&lt;/a&gt;, I wanted to talk about a piece of it that I put a lot of time into. Well, I actually poured way too much of my life into lots of parts of this game, and maybe I&amp;rsquo;ll write about those too, but for now let&amp;rsquo;s start where most games start: with the &lt;em&gt;game loop&lt;/em&gt;.&lt;/p&gt;

&lt;figure&gt;
  &lt;img class=&quot;framed&quot; src=&quot;/image/2014/08/snapshot.jpg&quot;&gt;
  &lt;figcaption&gt;Here&amp;rsquo;s the game I&amp;rsquo;m talking about. You can play it &lt;a href=&quot;http://munificent.github.io/hauberk/&quot;&gt;here&lt;/a&gt;. Don&amp;rsquo;t get freaked out by all of the text below! There&amp;rsquo;s interactive demos just a few paragraphs down!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;m &lt;a href=&quot;http://gameprogrammingpatterns.com/&quot;&gt;a bit obsessed&lt;/a&gt; with software architecture in games. Since this roguelike is my hobby project, I&amp;rsquo;ve fully indulged myself. You know that guy who always wanted to be a railroad engineer but ended up an accountant or something, and then spends years in his basement endlessly tinkering on a model railroad? I&amp;rsquo;m like that guy, but for software architecture. And roguelikes.&lt;/p&gt;

&lt;p&gt;That may be the nerdiest thing I&amp;rsquo;ve ever written, which, knowing me, is really saying something.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve refactored and rewritten the game loop more times than I can count (there&amp;rsquo;s probably some &amp;ldquo;iteration&amp;rdquo; metajoke hiding in this sentence), and I won&amp;rsquo;t drag you through the whole history of it. Instead, we&amp;rsquo;ll go through its current form, building it up a piece at a time.&lt;/p&gt;

&lt;p&gt;I have a couple of high-level goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The game engine should be &lt;em&gt;strictly&lt;/em&gt; separated from the user interface.&lt;/strong&gt; I&amp;rsquo;ve gone back and forth between a pixel art UI and a more old school ACSII-based one, and it&amp;rsquo;s important for me that the engine supports both. (The current Dart version is all ASCII-based right now, ironically rendered using the canvas API.) That means the engine can&amp;rsquo;t be coupled to any details of how the game is displayed to the user. Like a business app, I want a real model/view separation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monsters and player-controlled characters should be treated uniformly.&lt;/strong&gt; Most of the engine just deals with &amp;ldquo;&lt;a href=&quot;https://github.com/munificent/hauberk/blob/23bbc1feb2636a846b87eb0a95a2bbf3fbdc2184/lib/src/engine/actor.dart#L46&quot;&gt;actors&lt;/a&gt;&amp;rdquo;, the superclass of both &lt;a href=&quot;https://github.com/munificent/hauberk/blob/23bbc1feb2636a846b87eb0a95a2bbf3fbdc2184/lib/src/engine/monster.dart#L21&quot;&gt;&lt;code&gt;Monster&lt;/code&gt;&lt;/a&gt; and the player-controlled, gender-nonspecific &lt;a href=&quot;https://github.com/munificent/hauberk/blob/23bbc1feb2636a846b87eb0a95a2bbf3fbdc2184/lib/src/engine/hero/hero.dart&quot;&gt;&lt;code&gt;Hero&lt;/code&gt;&lt;/a&gt;. I want to minimize special treatment that the player&amp;rsquo;s avatar receives and treating it like just another entity in the game does that implicitly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Slicing up the game loop&lt;/h2&gt;

&lt;p&gt;Hauberk&amp;mdash;like most roguelikes&amp;mdash;is a &lt;em&gt;turn-based&lt;/em&gt; game. Each actor in the game makes a move one at a time. When it&amp;rsquo;s the player&amp;rsquo;s turn, all of the monsters halt, awkwardly motionless like the world&amp;rsquo;s strangest game of freeze tag, until the player makes their move.&lt;/p&gt;

&lt;p&gt;At the core of the game engine is the &lt;a href=&quot;http://gameprogrammingpatterns.com/game-loop.html&quot;&gt;game loop&lt;/a&gt;. Its job is to iterate over the actors in the level and tell each to take its turn. In a simple game, it would look something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gameLoop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stillPlaying&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, since the engine is decoupled from the user interface, it is driven externally. The engine has a main &lt;a href=&quot;https://github.com/munificent/hauberk/blob/fe0bdf614d5d00a5235b7a82d9d38c928928d34c/lib/src/engine/game.dart&quot;&gt;&lt;code&gt;Game&lt;/code&gt;&lt;/a&gt; class. The UI owns an instance of that and tells it to process. The engine only processes one &amp;ldquo;step&amp;rdquo; of gameplay before returning control back to the UI.&lt;/p&gt;

&lt;p&gt;(I&amp;rsquo;m being intentionally vague about &amp;ldquo;step&amp;rdquo; here. If I get a chance, I&amp;rsquo;ll write a follow-up post about how the engine&amp;rsquo;s game loop and the browser event loop interact. It&amp;rsquo;s pretty tricky.)&lt;/p&gt;

&lt;p&gt;What this means is that &lt;code&gt;Game&lt;/code&gt; needs to track the last actor who took a turn so it can pick up where it left off. Something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Game&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Actor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Astute readers like yourself are probably thinking this sounds like a good case for a &lt;a href=&quot;http://en.wikipedia.org/wiki/Generator_(computer_programming)&quot;&gt;generator&lt;/a&gt;. Indeed, in the previous C# incarnation of my game, &lt;a href=&quot;/2008/11/17/using-an-iterator-as-a-game-loop/&quot;&gt;I did exactly that&lt;/a&gt;. When Dart gets generators, I&amp;rsquo;ll probably use them. In the meantime, it&amp;rsquo;s just a bit more verbose.&lt;/p&gt;

&lt;h2&gt;Actions for actors&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve got a little resumable game loop now. When each actor&amp;rsquo;s turn comes up, its &lt;code&gt;update()&lt;/code&gt; is called and the actor does whatever it does. A monster might pick a direction to walk. Then, the consequences of that have to be handled: it may walk into another actor in which case that triggers combat. It needs to handle walking into a wall or a door.&lt;/p&gt;

&lt;p&gt;All told, even for a simple bit of behavior like &amp;ldquo;take a step&amp;rdquo;, there&amp;rsquo;s a decent amount of logic, but you&amp;rsquo;ll note that all of that applies equally well to monsters and heroes. Brave warriors can stumble into walls too, and the consequences are the same. It would be good to share code for this.&lt;/p&gt;

&lt;p&gt;The obvious answer is to push the walking code up into the shared &lt;code&gt;Actor&lt;/code&gt; base class. But if we do that for everything&amp;mdash;walking, melee combat, ranged attacks, inventory management, magic, etc.&amp;mdash;we&amp;rsquo;ll end up with an &lt;code&gt;Actor&lt;/code&gt; class that contains damn near the whole game. Super gross.&lt;/p&gt;

&lt;p&gt;Instead, we&amp;rsquo;ll make a classic game architecture decision. We&amp;rsquo;ll separate &lt;em&gt;deciding&lt;/em&gt; what behavior to perform from &lt;em&gt;executing&lt;/em&gt; the behavior. In other words, we&amp;rsquo;ll use the &lt;a href=&quot;http://gameprogrammingpatterns.com/command.html&quot;&gt;Command pattern&lt;/a&gt;. In Hauberk, these are called &lt;em&gt;actions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The game loop asks each actor to give it an action, then it tells the action to execute &lt;em&gt;itself&lt;/em&gt;, like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are different action classes for each atomic thing an actor in the world can do. There is a &lt;a href=&quot;https://github.com/munificent/hauberk/blob/53719994a29ba7b750bb78643f8b92d1f5516685/lib/src/engine/action_base.dart#L109&quot;&gt;&lt;code&gt;WalkAction&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/munificent/hauberk/blob/53719994a29ba7b750bb78643f8b92d1f5516685/lib/src/engine/action_base.dart#L154&quot;&gt;&lt;code&gt;OpenDoorAction&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/munificent/hauberk/blob/53719994a29ba7b750bb78643f8b92d1f5516685/lib/src/engine/action_base.dart#L192&quot;&gt;&lt;code&gt;EatAction&lt;/code&gt;&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;This pulls all of that behavior out of the base &lt;code&gt;Actor&lt;/code&gt; class. Even better, it separates all of the actions from &lt;em&gt;each other&lt;/em&gt;. If you&amp;rsquo;re adding or changing a thing that actors can do, you can just poke at one isolated little action class. It feels nice and decoupled and it&amp;rsquo;s easy to add new actions to the game. (As of today, there are nineteen different actions, and I expect to add a bunch more.)&lt;/p&gt;

&lt;p&gt;It also, of course, helps us treat monsters and heroes uniformly. Since the &lt;code&gt;Action&lt;/code&gt; classes all work on instances of &lt;code&gt;Actor&lt;/code&gt;, they can all be used by monsters and heroes alike. (There are some exceptions since heroes have some capabilities monsters don&amp;rsquo;t have. Right now, monsters don&amp;rsquo;t have inventory so all of the inventory management actions don&amp;rsquo;t apply to them.)&lt;/p&gt;

&lt;h2&gt;Acting at speed&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve got a basic loop working now, but our game is a bit &lt;em&gt;too&lt;/em&gt; turn-based. Every monster and the hero all proceed in lockstep. You move one step, they all move one step, kind of like the ancient &lt;a href=&quot;http://en.wikipedia.org/wiki/Robots_(BSD_game)&quot;&gt;Robots&lt;/a&gt; game. You can never outrun or be outrun. See for yourself:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;same-speed&quot; tabindex=&quot;1&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Use arrow keys or &lt;code&gt;iopkl;,./&lt;/code&gt; to move. Press &lt;code&gt;t&lt;/code&gt; to teleport.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;To fix that, we want actors to move at different &lt;em&gt;speeds&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Of course, this is &amp;ldquo;speed&amp;rdquo; in the turn-based sense, not literally moving quicker in realtime. What it means is that a &amp;ldquo;faster&amp;rdquo; actor gets to take turns more &lt;em&gt;frequently&lt;/em&gt; than other actors. If you&amp;rsquo;re twice as fast as a green slime, then you&amp;rsquo;ll get to take two steps for every one it gets.&lt;/p&gt;

&lt;p&gt;This mechanic is &lt;em&gt;de rigueur&lt;/em&gt; in roguelikes, and the literature is &lt;a href=&quot;http://www.roguebasin.com/index.php?title=An_elegant_time-management_system_for_roguelikes&quot;&gt;rife&lt;/a&gt; &lt;a href=&quot;http://www.roguebasin.com/index.php?title=A_priority_queue_based_turn_scheduling_system&quot;&gt;with&lt;/a&gt; &lt;a href=&quot;http://doryen.eptalys.net/forum/index.php?topic=1596.0&quot;&gt;ways&lt;/a&gt; &lt;a href=&quot;http://ironypolicy.wordpress.com/2014/02/05/possession-2-speed-systems-in-roguelikes/&quot;&gt;to&lt;/a&gt; implement it. The system I&amp;rsquo;m using is almost exactly &lt;a href=&quot;http://www.faqs.org/faqs/games/roguelike/angband-faq/&quot;&gt;what Angband uses&lt;/a&gt;, because it&amp;rsquo;s awesome.&lt;/p&gt;

&lt;p&gt;It works like this: Every actor has an &lt;em&gt;energy&lt;/em&gt; level. Each time the game loop reaches an actor, it grants it a bit of energy. When the actor&amp;rsquo;s energy reaches a certain threshold, it has enough to take a turn and perform an action. Otherwise, the game loop just moves on to the next actor. It may take several cranks through the game loop before an actor accumulates enough juice to actually take a turn. (And, in fact, for all but the fastest actors, it does.)&lt;/p&gt;

&lt;p&gt;When the actor performs an action, that burns energy, and they&amp;rsquo;re back in the &amp;ldquo;waiting to get enough energy to go&amp;rdquo; state. Right now, all actions consume the same amount of energy, which means every action takes the same amount of &amp;ldquo;time&amp;rdquo; to perform. I &lt;em&gt;could&lt;/em&gt; vary this so that, for example, archers could shoot arrows more frequently than they could swing a sword.&lt;/p&gt;

&lt;p&gt;The way &lt;em&gt;speed&lt;/em&gt; comes into play is simple: &lt;em&gt;faster actors get more energy each turn.&lt;/em&gt; That means they&amp;rsquo;ll cross the threshold in fewer revolutions of the game loop, so they&amp;rsquo;ll get to move more often. It&amp;rsquo;s as simple as that.&lt;/p&gt;

&lt;p&gt;The neat thing about it is that by accumulating energy over several turns, you can have actors that move at arbitrary fractions of each other&amp;rsquo;s speed. You could have an actor that gets five moves for every seven moves another actor gets if you wanted. (Of course, what you&amp;rsquo;d see during game play is that every now and then the second actor would get a double turn. It&amp;rsquo;s just that the &amp;ldquo;every now and then&amp;rdquo; averages out to 7/5 over time.)&lt;/p&gt;

&lt;p&gt;Enough verbiage, let&amp;rsquo;s see it in action:&lt;/p&gt;

&lt;figure&gt;
  &lt;canvas id=&quot;speed-bars&quot; tabindex=&quot;2&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;
  &lt;figcaption&gt;Same controls before but the game loop is slowed down so you can watch it parcel out energy.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The &lt;code&gt;&amp;gt;&lt;/code&gt; points to the actor whose turn it is. It&amp;rsquo;s usually stuck waiting on you. After you make a move, you can watch the game loop race around, doling out bits of energy. When an actor&amp;rsquo;s bar reaches the right edge, it takes a move and the bar resets.&lt;/p&gt;

&lt;p&gt;The cool thing about this system is that applies to all &lt;em&gt;actors&lt;/em&gt;. Some game engines update the hero separately from monsters in the main game loop, but that makes speed much trickier to handle. By treating the hero as just another actor, the hero can be both slower and faster than other monsters automatically.&lt;/p&gt;

&lt;h2&gt;The one special thing about heroes&lt;/h2&gt;

&lt;p&gt;Treating the hero as just another actor is mostly swell, but there &lt;em&gt;is&lt;/em&gt; one thing about heroes that makes them unique&amp;mdash;they&amp;rsquo;re controlled by the player. The game loop I showed runs fine as long as actors generate their own actions. That&amp;rsquo;s true in the case of AI-driven monsters, but the hero can&amp;rsquo;t see through your glassy computer screen and discern your intentions through cyber-telepathy. It needs user input.&lt;/p&gt;

&lt;p&gt;We already have two constraints that make this harder:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Because we want to separate the engine from the user interface, it can&amp;rsquo;t directly call into input-handling code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Because the game runs in a browser, it can&amp;rsquo;t &lt;em&gt;block&lt;/em&gt; waiting for user input. The browser don&amp;rsquo;t play &amp;lsquo;dat. You have to return to the event loop and let it tell &lt;em&gt;you&lt;/em&gt; when an event comes in.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the game loop asks a hero for its action, the hero can&amp;rsquo;t just stop the game and wait for the player to push a button. Instead, we&amp;rsquo;ll let the user interface &lt;em&gt;inject&lt;/em&gt; input into the game. The input handling code can create an action for the hero &lt;em&gt;ex-nihilo&lt;/em&gt; and jam it in the engine&amp;rsquo;s piehole, like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handleInput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Keyboard&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keyboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keyboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastPressed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;G:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setNextAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PickUpAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;I:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;O:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;P:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;K:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;L:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NONE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;SEMICOLON:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;COMMA:&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;PERIOD:&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;SLASH:&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Direction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setNextAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WalkAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That call to &lt;code&gt;setNextAction()&lt;/code&gt; stuffs the given action into a field in the hero. When the game loop asks the hero what it wants to do, it barfs that back up:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Hero&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Actor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_nextAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setNextAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_nextAction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_nextAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Only perform it once.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_nextAction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Other heroic stuff...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(In the actual game, there&amp;rsquo;s actually a level of indirection here to handle &lt;a href=&quot;https://github.com/munificent/hauberk/blob/11c5ca5d258dfdae20118c7a4dcc82e50ceb67de/lib/src/engine/hero/hero.dart#L301&quot;&gt;multi-step behaviors like running&lt;/a&gt;, but we&amp;rsquo;ll ignore that here.)&lt;/p&gt;

&lt;p&gt;This keeps the engine from reaching out to the user interface and lets the UI pass input to the engine at its leisure. The only problem is what happens when the game engine is told to process the hero&amp;rsquo;s turn and the UI hasn&amp;rsquo;t given it an input yet.&lt;/p&gt;

&lt;p&gt;To handle that, the loop just checks for the actor failing to cough up an action. When that happens, it bails and returns control back to the user interface:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Don&amp;#39;t advance past the actor if it didn&amp;#39;t take a turn.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the interface tells the game engine to process but hasn&amp;rsquo;t given instructions to the hero, the engine does nothing and bounces control back to the UI. Note how &lt;code&gt;setNextAction()&lt;/code&gt; can be called at any point in time. This works seamlessly with the speed system without the UI having to be aware of it. It just throws hero actions at the engine and tells it to process. The engine takes care to ensure the simulation only ratchets forward at the right time.&lt;/p&gt;

&lt;p&gt;In fact, now that I think about it, if you had multiple player-controlled heroes driven by different inputs, it would automatically handle that too. They could even be coming over a network and the engine won&amp;rsquo;t care. Groovy.&lt;/p&gt;

&lt;p&gt;The way this interacts with the browser&amp;rsquo;s own event loop is actually a good bit more complex than this when you take into account visual effects, but I think I&amp;rsquo;ll have to save that for another post. For now, let&amp;rsquo;s keep our attention on the pristine confines of the engine.&lt;/p&gt;

&lt;h2&gt;Fat fingers&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;re pretty far along with our game loop now. We&amp;rsquo;ve got it doing the stuff it &lt;em&gt;needs&lt;/em&gt; to do, so we can start looking at making the game more pleasantly usable. Usability means &lt;em&gt;fallibility&lt;/em&gt;. People make mistakes, and usability is about accommodating that.&lt;/p&gt;

&lt;p&gt;For example, let&amp;rsquo;s say the player tries to make the hero walk into a wall. Right now, that creates a walk action. When action is processed it prevents the hero from walking through the wall, but it still &lt;em&gt;burns that turn&lt;/em&gt;. If he&amp;rsquo;s trying to run away from a foul beastie, that slip up could cost the hero his life. Some games are OK with that, but I don&amp;rsquo;t want to be that punishing. Roguelikes are unforgiving enough as it is.&lt;/p&gt;

&lt;p&gt;The demos so far work this way now. Go back and try running into a wall. See how your mortal enemies approach in the midst of your ineptitude? That&amp;rsquo;s what we want to fix. When the player tries to do an action that isn&amp;rsquo;t possible, we want to make sure we don&amp;rsquo;t waste a turn on it.&lt;/p&gt;

&lt;p&gt;One way to handle that would be to validate the turn in the user interface. In the input handling, we check the tile that the hero wants to walk into and make sure it&amp;rsquo;s a floor tile. If it isn&amp;rsquo;t, the user interface shows an error and doesn&amp;rsquo;t send an action to the game. From the engine&amp;rsquo;s perspective, it only receives beautiful, correct user actions.&lt;/p&gt;

&lt;p&gt;But doing that validation is actually pretty complex. Maybe the hero has an insubstantiation spell and &lt;em&gt;can&lt;/em&gt; walk through walls right now. Maybe the tile isn&amp;rsquo;t floor but is something the hero can tunnel through, but only if they have a shovel in their inventory.&lt;/p&gt;

&lt;p&gt;What I&amp;rsquo;m describing are &lt;em&gt;game mechanics&lt;/em&gt;, and game mechanics belong in the engine. In particular, most of them belong in actions. We&amp;rsquo;ll put the solution to this problem in there too. When an action is processed, we&amp;rsquo;ll let it return a value indicating success. If it fails, the game loop considers it to have never happened. It&amp;rsquo;s as simple as:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;success&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Don&amp;#39;t advance if the action failed.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This makes the engine more robust: you can throw arbitrary actions at it and it will handle them gracefully. It also keeps all of the code for a single mechanic&amp;mdash;including validation&amp;mdash;in one place: in the relevant action. Yay for encapsulation!&lt;/p&gt;

&lt;p&gt;Now, try braining yourself against the dungeon&amp;rsquo;s stone boundary:&lt;/p&gt;

&lt;canvas id=&quot;safe-fail&quot; tabindex=&quot;3&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;

&lt;h2&gt;Do what I mean, not what I said&lt;/h2&gt;

&lt;p&gt;Success/failure handles cases where the action the player picked is totally bogus, but sometimes the game can infer out what they were &lt;em&gt;trying&lt;/em&gt; to do. For example, if you try to make the hero walk into a closed door instead of using the dedicated &amp;ldquo;open door&amp;rdquo; command, odds are pretty good you want to open the damned door. Likewise, if you try to walk into a monster, that&amp;rsquo;s a good time to consider swinging a sword.&lt;/p&gt;

&lt;p&gt;I know this sounds obvious, but you&amp;rsquo;d be surprised how many roguelikes don&amp;rsquo;t do this. Improving usability is one of my main goals for my game, so I care about this stuff. I&amp;rsquo;ve got a pretty simple solution too.&lt;/p&gt;

&lt;p&gt;When an action is validating itself, it can fail outright like we saw, but it can also respond with an &lt;em&gt;alternate action&lt;/em&gt;. It lets the action say, &amp;ldquo;no, you really mean this&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Since the &lt;code&gt;perform()&lt;/code&gt; method on &lt;code&gt;Action&lt;/code&gt; can return success, failure, or another action, we&amp;rsquo;ll make a little class to wrap that up:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ActionResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SUCCESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FAILURE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;/// An alternate [Action] that should be performed instead of&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;/// the one that failed.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alternative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;/// `true` if the [Action] was successful and energy should&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;/// be consumed.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;succeeded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;succeeded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alternative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alternate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alternative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;succeeded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When an action is executing, it returns &lt;code&gt;ActionResult.SUCCESS&lt;/code&gt; to say everything went fine, &lt;code&gt;ActionResult.FAILURE&lt;/code&gt; to say nothing happened, or it can return an &lt;code&gt;ActionResult&lt;/code&gt; with &lt;code&gt;.alternate&lt;/code&gt; pointing to a new action to perform instead.&lt;/p&gt;

&lt;p&gt;The game loop processes that:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;succeeded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alternate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alternate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_currentActor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We do this in a loop because an alternate may itself return an alternate, so we keep trying until we bottom out on an action that succeeds or fails. This turns out to be a handy feature for a number of things in the full game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When you use an item, the &amp;ldquo;use item&amp;rdquo; action looks up the specific thing the item does (shoot a fireball, teleport, etc.) and returns that as an alternate. When you &amp;ldquo;use&amp;rdquo; an equippable item, it returns the &amp;ldquo;equip&amp;rdquo; action as an alternate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If an actor &amp;ldquo;walks&amp;rdquo; but in no direction, it becomes a &amp;ldquo;rest&amp;rdquo; action which regains a bit of health.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If an actor walks into a door, it returns the &amp;ldquo;open door&amp;rdquo; action as an alternate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If an actor tries to walk into another, it returns the &amp;ldquo;attack&amp;rdquo; melee action as an alternate.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last three are particularly handy because they&amp;rsquo;re equally applicable to monsters. The monster AI code doesn&amp;rsquo;t have to check for doors or opponents. Instead it just tries to make the monster walk where it wants to go and the action system handles opening doors to get there and attacking the hero when it reaches them. When the monster can&amp;rsquo;t figure out where to go, it rests automatically.&lt;/p&gt;

&lt;p&gt;Believe me, anything you can do to simplify your AI code is a good idea. Enough jibber-jabber, let&amp;rsquo;s see it in action:&lt;/p&gt;

&lt;canvas id=&quot;alternate&quot; tabindex=&quot;4&quot;&gt;Sorry, you need canvas support for this demo.&lt;/canvas&gt;

&lt;p&gt;Notice the little room has a door now. If you try to walk into it, the game loop will go through the walk&amp;rsquo;s alternate action to do the open. You can close it by pressing &amp;ldquo;C&amp;rdquo; when standing next to it.&lt;/p&gt;

&lt;p&gt;The wizard is smart enough to open doors too (sorry, troll and slug, no Mensa membership for you) and no changes to the pathfinding AI were needed to enable it. He just tries to walk &lt;em&gt;through&lt;/em&gt; the door and miraculously succeeds.&lt;/p&gt;

&lt;h2&gt;The end&amp;hellip; &lt;em&gt;or is it?&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;Crap, I&amp;rsquo;ve already burned three thousand words of your attention and there&amp;rsquo;s still cool stuff to talk about! I&amp;rsquo;m gonna have to split this into a two parter.&lt;/p&gt;

&lt;p&gt;What we have now is a pretty solid (in my opinion, naturally) game loop. Defining behavior in actions lets us treat the player-controlled hero and monsters uniformly. We&amp;rsquo;ve got a flexible speed system, and it&amp;rsquo;s all nicely separated from the user interface.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re building a relatively simple turn-based game, this is probably enough.&lt;/p&gt;

&lt;p&gt;But, while ASCII-art-based roguelikes aren&amp;rsquo;t known for their visual spectacle, I want something that with a bit more pizazz than what I described here can dish up. I want the player to see an arrow arc across the room before plunking into the meaty face of a troll. I want fireballs to flare outwards in a ring of death. And when that flame touches incendiary items laying on the ground, those should in turn trigger a cascading conflagration.&lt;/p&gt;

&lt;p&gt;The game loop I have in the full game can do that. When I can find the time to carve out a few more standalone demos and hack up some prose, I&amp;rsquo;ll show you how. In the meantime, the code for the game is &lt;a href=&quot;https://github.com/munificent/hauberk&quot;&gt;here&lt;/a&gt;, and the code for the demos in this post are &lt;a href=&quot;https://github.com/munificent/a-turn-based-game-loop&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to try out the game, you can &lt;a href=&quot;http://munificent.github.io/hauberk/&quot;&gt;play it here&lt;/a&gt;.&lt;/p&gt;

&lt;script type=&quot;application/dart&quot; src=&quot;/code/2014-07-15-a-turn-based-game-loop/main.dart&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/code/2014-07-15-a-turn-based-game-loop/packages/browser/dart.js&quot;&gt;&lt;/script&gt;
</content>
  </entry>
  
  <entry>
    <id>http://journal.stuffwithstuff.com/2014/07/05/dropping-loot</id>
    <link type="text/html" rel="alternate" href="http://journal.stuffwithstuff.com/2014/07/05/dropping-loot"/>
    <title>Dropping Loot</title>
    <published>2014-07-05T00:00:00-07:00</published>
    <updated>2014-07-05T00:00:00-07:00</updated>
    <author>
      <name>Robert Nystrom</name>
      <uri>http://journal.stuffwithstuff.com/</uri>
    </author>
    <content type="html">&lt;p&gt;I got started hacking on my own roguelike after spending several years avidly playing &lt;a href=&quot;http://rephial.org/&quot;&gt;Angband&lt;/a&gt;. Like most projects, I had a few itches I wanted to scratch and it kind of took on a life of its own. One thing that annoyed me about Angband was how monsters dropped loot when they died.&lt;/p&gt;

&lt;p&gt;In Angband, any monster that drops stuff can drop pretty much anything. Monsters have a level, and if they drop loot, it just randomly picks any item near the monsters level. This bugged me for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It felt flavorless and unrealistic.&lt;/strong&gt; For example, the description of a novice mage is:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;The Novice mage  (Red &amp;#39;p&amp;#39;)
=== Num:38  Lev:2  Rar:1  Spd:+0  Hp:6d4  Ac:6  Exp:6
He is leaving behind a trail of dropped spell components.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But when you hack one to pieces, he&amp;rsquo;s as likely to drop a sword as he
is anything magical. This makes monsters feel too similar each other: each one is basically a spin on the one giant Wheel Of Loot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It made it impossible for the player to seek certain items.&lt;/strong&gt; Let&amp;rsquo;s say you&amp;rsquo;ve got a good kit of armor except you really could use some high quality boots. How do you fill in that gap?&lt;/p&gt;

&lt;p&gt;In Angband, the answer is &amp;ldquo;kill a whole ton of stuff and wade through piles of loot you don&amp;rsquo;t care about&amp;rdquo;. Especially near the end game where you&amp;rsquo;re looking for just a few specific pieces of gear, you spend a &lt;em&gt;lot&lt;/em&gt; of time just killing dragons and hunting through mountains of loot. 95% of it gets left on the ground.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wanted to solve this by making different monsters drop different stuff. Kill a warrior, and you should get weapons and armor. Kill a wizard, get wands and scrolls.&lt;/p&gt;

&lt;h2&gt;Monster-specific loot&lt;/h2&gt;

&lt;p&gt;My first pass at this was to give each monster its own set of drops. I had already made monsters data-driven. I came up with my own little text format so monsters were defined in text something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;dwarf miner
    color     = DarkGray
    depth     = 22
    health    = 44
    attacks
        hammers = 15t5
    description
        Covered from head to toe is dust and dirt, you can barely
        make out the form of this weary dwarf.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For each monster (or at least, each one that drops loot), I added a &amp;ldquo;drops&amp;rdquo; section, like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;drops
    hammer (50%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And, behold, kill a dwarven miner and there&amp;rsquo;s a fifty-fifty chance he&amp;rsquo;ll drop a hammer. But dwarves like gems too, right? So I added that in too. Only the problem is that there&amp;rsquo;s a bunch of different kinds of gems, so I ended up with something like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;drops
    hammer (50%)
    amethyst (10%)
    sapphire (7%)
    emerald (4%)
    ruby (3%)
    diamond (2%)
    blue diamond (1%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It uses the percentages to pick one of the drops. Notice how the better gems are rarer? That&amp;rsquo;s fine for a miner, which is a pretty weak dwarf, but a dwarf chieftan should tend to drop better gems:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;drops
    amethyst (3%)
    sapphire (5%)
    emerald (8%)
    ruby (10%)
    diamond (8%)
    blue diamond (5%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now consider that there&amp;rsquo;s a few different types of hammers too&amp;hellip; Things got pretty nasty pretty quickly. It was a huge chore to maintain these giant tuned drop tables for each of potentially hundreds of monsters. Ugh.&lt;/p&gt;

&lt;p&gt;The first thing I realized was that there was a lot of overlap between monsters. Dwarven miners and dwarven warriors drop the same gems with the same frequency. So I made &amp;ldquo;macros&amp;rdquo; in my drop language. I could define:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;(gem)
    hammer (50%)
    amethyst (10%)
    sapphire (7%)
    emerald (4%)
    ruby (3%)
    diamond (2%)
    blue diamond (1%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in dwarven miner and warrior, just add:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;drops
    (gem)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;(gem)&lt;/code&gt; would then expand to that little weighted table of gems. That worked fine when the probabilities of each gem were the same, but it meant I couldn&amp;rsquo;t reuse these tables across dwarves of different &lt;em&gt;difficulty&lt;/em&gt;. Stronger dwarves drop the same gems but with different probabilities.&lt;/p&gt;

&lt;p&gt;So I came up with a different kind of drop that selects from a bunch of child drops based on &lt;em&gt;level&lt;/em&gt;. This let me define:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;(gem)
    one near level
        amethyst (23)
        sapphire (38)
        emerald (52)
        ruby (62)
        diamond (87)
        blue diamond (95)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &amp;ldquo;one near level&amp;rdquo; part would take the monster&amp;rsquo;s level into account, plus a bit of randomness, to pick child drop from within it. Now I could reuse &lt;code&gt;(gem)&lt;/code&gt; across a range of different difficulties. Of course, I still had to define lots of tables for all of these different &amp;ldquo;kinds&amp;rdquo; of drops. There was a table for gems, stones, hammers, daggers, etc. Piles of data.&lt;/p&gt;

&lt;p&gt;After all of that, I found it wasn&amp;rsquo;t fun to play. The problem was that even with these tables, killing a monster was&amp;hellip; &lt;em&gt;boring&lt;/em&gt;. Every time you killed a drwarf, you knew what you were going to get. You might get a better gem (yay), but nothing surprising.&lt;/p&gt;

&lt;h2&gt;Simpler Sequences&lt;/h2&gt;

&lt;p&gt;A few years ago, I ported the game to &lt;a href=&quot;https://www.dartlang.org/&quot;&gt;Dart&lt;/a&gt;. When I did, I tried to simplify as many things as I could. I didn&amp;rsquo;t want to rewrite this whole giant DSL macro language thing. Instead, I noticed that every item seemed to be a member of some sequence. Emeralds are always in a sequence of gems, a hammer is in a sequence with warhammers and mattocks, etc.&lt;/p&gt;

&lt;p&gt;Instead of building some complex general-purpose loot DSL and then implementing this logic using that, I just built sequences directly into the loot code. When defining a monster (now we&amp;rsquo;re in Dart code), you&amp;rsquo;d list the drops:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;goblin peon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lightBrown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;drop:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Spear&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &amp;ldquo;Spear&amp;rdquo; means it tends to drop spears. But it also implicitly means it can drop other items in the same sequence that spears are in. This lets you express both a sequence and how deep into the sequence a monster should tend to drop. To have a stronger monster drop items from the deep end of the sequence, just name an item from that end.&lt;/p&gt;

&lt;p&gt;This let me express pretty much what I could before, but it was a hell of a lot simpler. The only limitation is that an item could only be a part of one sequence. In practice, that works OK.&lt;/p&gt;

&lt;p&gt;Unfortunately, though, it didn&amp;rsquo;t solve the boringness problem. I learned the hard way that a huge part of the fun of roguelikes is the &amp;ldquo;lottery effect&amp;rdquo;. Every time you kill a monster there should be a small chance of getting something really amazing. That &amp;ldquo;maybe this one will be the big one&amp;rdquo; anticipation is one of the key emotions in the game.&lt;/p&gt;

&lt;p&gt;With sequences, you could get something good, but never something &lt;em&gt;surprising&lt;/em&gt;. Eventually, I hit upon a solution and, so far, I really like it.&lt;/p&gt;

&lt;h2&gt;Item Groups&lt;/h2&gt;

&lt;p&gt;Instead of sequences of items, I now have a &lt;em&gt;hierarchy&lt;/em&gt; of them. So, for example, a stilleto is:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;&lt;/span&gt;equipment/weapon/dagger/Stilleto
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;m not generally a fan of hierarchies but I found it surprisingly easy to lump almost every item into one. Items also have a &amp;ldquo;level&amp;rdquo;, which describes their relative value. Higher level stuff is better.&lt;/p&gt;

&lt;p&gt;When specifying a drop for a monster, I can specify an item name to drop that specific item. But I can also specify the name of part of the path and a level, like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;goblin peon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lightBrown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;drop:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;spear:3&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;healing:2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;meander:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;flags:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;few open-doors&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;&amp;quot;spear:3&amp;quot;&lt;/code&gt; means &amp;ldquo;drop something from the &amp;lsquo;spear&amp;rsquo; group around level 3&amp;rdquo;. You don&amp;rsquo;t have to specify the entire path since path components are unique. So &amp;ldquo;spear&amp;rdquo; is equivalent to &amp;ldquo;equipment/weapon/spear&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;So far, this is pretty much equivalent to the sequences from before. The neat part is what happens when the drop is generated. When picking an item, there&amp;rsquo;s a small chance that it will walk up the group chain. So &amp;ldquo;spear:3&amp;rdquo; will usually drop a spear, but there&amp;rsquo;s a chance it will drop any weapon (the parent group). There&amp;rsquo;s an even smaller chance it will drop any piece of equipment (the grandparent).&lt;/p&gt;

&lt;p&gt;Any monster has a chance of dropping almost any item, so you have that pleasant anticipation. At the same time, the probabilities are weighted so that each monster still has a unique &amp;ldquo;feel&amp;rdquo; to their drops, and you can seek out monsters that are more likely to drop what you want.&lt;/p&gt;

&lt;p&gt;When specifying a drop, you can also directly specify one of the parent groups. For example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;goblin warrior&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;drop:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;equipment:6&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;meander:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;flags:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;protective open-doors&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, the &lt;code&gt;&amp;quot;equipment:6&amp;quot;&lt;/code&gt; means a goblin may drop &lt;em&gt;any&lt;/em&gt; kind of equipment. This makes it really easy to specify monsters that define wide sets of drops. That&amp;rsquo;s good for high level boss monsters that can serve up an assortment of loot.&lt;/p&gt;

&lt;p&gt;At the same time, defining the items is pretty simple. You basically just need to categorize and assign a level for each item. It looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot; data-lang=&quot;dart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;r&amp;quot;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;equipment/weapon/spear&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Pointed Stick&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;brown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Spear&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Angon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lightGray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Lance&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Partisan&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;darkGray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;stab[s]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The numbers after the name are their levels.) Once you do that, all of the rest of the drop behavior falls out naturally. If I add a new item to an existing group, every monster will then start dropping it, with the right probabilities.&lt;/p&gt;
</content>
  </entry>
  

</feed>
