297 lines
No EOL
29 KiB
HTML
297 lines
No EOL
29 KiB
HTML
<!DOCTYPE html>
|
|
<html lang='en'><head><meta charset='utf-8' /><meta name='pinterest' content='nopin' /><link href='../../../../static/css/style.css' rel='stylesheet' type='text/css' /><link href='../../../../static/css/print.css' rel='stylesheet' type='text/css' media='print' /><title>The Caves of Clojure: Part 3.4 / Steve Losh</title></head><body><header><a id='logo' href='https://stevelosh.com/'>Steve Losh</a><nav><a href='../../../index.html'>Blog</a> - <a href='https://stevelosh.com/projects/'>Projects</a> - <a href='https://stevelosh.com/photography/'>Photography</a> - <a href='https://stevelosh.com/links/'>Links</a> - <a href='https://stevelosh.com/rss.xml'>Feed</a></nav></header><hr class='main-separator' /><main id='page-blog-entry'><article><h1><a href='index.html'>The Caves of Clojure: Part 3.4</a></h1><p class='date'>Posted on July 11th, 2012.</p><p>This post is part of an ongoing series. If you haven't already done so, you
|
|
should probably start at <a href="../caves-of-clojure-01/index.html">the beginning</a>.</p>
|
|
|
|
<p>This entry (kind of) corresponds to <a href="http://trystans.blogspot.com/2011/08/roguelike-tutorial-03-scrolling-through.html">post three in Trystan's
|
|
tutorial</a>.</p>
|
|
|
|
<p>If you want to follow along, the code for the series is <a href="http://bitbucket.org/sjl/caves/">on Bitbucket</a> and
|
|
<a href="http://github.com/sjl/caves/">on GitHub</a>. Update to the <code>entry-03-4</code> tag to see the code as it stands
|
|
after this post.</p>
|
|
|
|
<ol class="table-of-contents"><li><a href="index.html#s1-summary">Summary</a></li><li><a href="index.html#s2-record-creation">Record Creation</a></li><li><a href="index.html#s3-update-in">update-in</a></li><li><a href="index.html#s4-namespaces">Namespaces</a></li><li><a href="index.html#s5-results">Results</a></li></ol>
|
|
|
|
<h2 id="s1-summary"><a href="index.html#s1-summary">Summary</a></h2>
|
|
|
|
<p>In the last post I said that the next post would be about Trystan's fourth
|
|
entry. I lied. I'm going to do a short entry about refactoring before I move
|
|
on, because I don't want to clutter up later ones with this stuff.</p>
|
|
|
|
<h2 id="s2-record-creation"><a href="index.html#s2-record-creation">Record Creation</a></h2>
|
|
|
|
<p>Hacker News user bitsai <a href="https://news.ycombinator.com/item?id=4220141">told me about</a> a new syntax for creating records in
|
|
Clojure 1.3, so I updated all the <code>(new Foo)</code> calls to use that.</p>
|
|
|
|
<p>One example is the <code>new-game</code> function. Before:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> new-game <span class="paren2">[<span class="code"></span>]</span>
|
|
<span class="paren2">(<span class="code">assoc <span class="paren3">(<span class="code">new Game nil <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">new UI <span class="keyword">:start</span></span>)</span></span>]</span> nil</span>)</span>
|
|
<span class="keyword">:location</span> <span class="paren3">[<span class="code">40 20</span>]</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>After:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> new-game <span class="paren2">[<span class="code"></span>]</span>
|
|
<span class="paren2">(<span class="code">assoc <span class="paren3">(<span class="code">->Game nil <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">->UI <span class="keyword">:start</span></span>)</span></span>]</span> nil</span>)</span>
|
|
<span class="keyword">:location</span> <span class="paren3">[<span class="code">40 20</span>]</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>It's certainly not too impressive from a "characters saved" point of view. But
|
|
this little change matters more than it might appear at first glance.</p>
|
|
|
|
<p>Imagine you define a record in Clojure:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns a</span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defrecord</span></i> Foo <span class="paren2">[<span class="code"></span>]</span></span>)</span></span></code></pre>
|
|
|
|
<p>And then in another namespace you want to use it:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns b
|
|
<span class="paren2">(<span class="code"><span class="keyword">:use</span> a</span>)</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code">new Foo</span>)</span></span></code></pre>
|
|
|
|
<p>This will explode, because <code>Foo</code> is actually a Java class, so you need to import
|
|
it:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns b
|
|
<span class="paren2">(<span class="code"><span class="keyword">:import</span> a.Foo</span>)</span>
|
|
<span class="paren2">(<span class="code"><span class="keyword">:use</span> a</span>)</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code">new Foo</span>)</span></span></code></pre>
|
|
|
|
<p>This is one example of Clojure's Java underpinnings leaking through.</p>
|
|
|
|
<p>In Clojure 1.3, <code>defrecord</code> will automatically generate a "factory function"
|
|
that creates the record, and you can <code>require</code> or <code>use</code> <em>that</em> like any other
|
|
function, so you don't need to screw around with a Java interop feature
|
|
(<code>import</code>) to use a pure Clojure feature.</p>
|
|
|
|
<p>This is a good thing. It means that progress is being made toward patching the
|
|
places that Java leaks into Clojure. It gives me hope that some day I'll feel
|
|
okay recommending Clojure to people without Java experience.</p>
|
|
|
|
<p>I updated all the <code>(new ...)</code> calls to use the new-style factory functions.
|
|
I won't paste them all here, but if you're following along you'll want to <code>grep
|
|
-R 'new ' .</code> and update the rest now.</p>
|
|
|
|
<h2 id="s3-update-in"><a href="index.html#s3-update-in">update-in</a></h2>
|
|
|
|
<p>Next is a tiny change that's just a bit cleaner. Alan Malloy <a href="https://twitter.com/alanmalloy/status/222748536595423232">told me</a> about
|
|
it. In the <code>process-input</code> function for the <code>:play</code> UI, the code to handle
|
|
smoothing the world looked like this:</p>
|
|
|
|
<pre><code><span class="code">\s <span class="paren1">(<span class="code">assoc game <span class="keyword">:world</span> <span class="paren2">(<span class="code">smooth-world <span class="paren3">(<span class="code"><span class="keyword">:world</span> game</span>)</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>This can be done much more cleanly using <code>update-in</code>:</p>
|
|
|
|
<pre><code><span class="code">\s <span class="paren1">(<span class="code">update-in game <span class="paren2">[<span class="code"><span class="keyword">:world</span></span>]</span> smooth-world</span>)</span></span></code></pre>
|
|
|
|
<p>Nice.</p>
|
|
|
|
<h2 id="s4-namespaces"><a href="index.html#s4-namespaces">Namespaces</a></h2>
|
|
|
|
<p>I said in an earlier post that I tend to leave things in one file until I feel
|
|
like they need to be pulled out. Well, that time has come.</p>
|
|
|
|
<p>First I pulled the UI drawing code into its own file: <code>ui/drawing.clj</code>. It
|
|
looks like this (nothing has changed, it's just in a file of its own now):</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.ui.drawing
|
|
<span class="paren2">(<span class="code"><span class="keyword">:require</span> <span class="paren3">[<span class="code">lanterna.screen <span class="keyword">:as</span> s</span>]</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code">def screen-size <span class="paren2">[<span class="code">80 24</span>]</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> clear-screen <span class="paren2">[<span class="code">screen</span>]</span>
|
|
<span class="paren2">(<span class="code"><i><span class="symbol">let</span></i> <span class="paren3">[<span class="code"><span class="paren4">[<span class="code">cols rows</span>]</span> screen-size
|
|
blank <span class="paren4">(<span class="code">apply str <span class="paren5">(<span class="code">repeat cols \space</span>)</span></span>)</span></span>]</span>
|
|
<span class="paren3">(<span class="code">doseq <span class="paren4">[<span class="code">row <span class="paren5">(<span class="code">range rows</span>)</span></span>]</span>
|
|
<span class="paren4">(<span class="code">s/put-string screen 0 row blank</span>)</span></span>)</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmulti</span></i> draw-ui
|
|
<span class="paren2">(<span class="code">fn <span class="paren3">[<span class="code">ui game screen</span>]</span>
|
|
<span class="paren3">(<span class="code"><span class="keyword">:kind</span> ui</span>)</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> draw-ui <span class="keyword">:start</span> <span class="paren2">[<span class="code">ui game screen</span>]</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 0 <span class="string">"Welcome to the Caves of Clojure!"</span></span>)</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 1 <span class="string">"Press any key to continue."</span></span>)</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 2 <span class="string">""</span></span>)</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 3 <span class="string">"Once in the game, you can use enter to win,"</span></span>)</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 4 <span class="string">"and backspace to lose."</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> draw-ui <span class="keyword">:win</span> <span class="paren2">[<span class="code">ui game screen</span>]</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 0 <span class="string">"Congratulations, you win!"</span></span>)</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 1 <span class="string">"Press escape to exit, anything else to restart."</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> draw-ui <span class="keyword">:lose</span> <span class="paren2">[<span class="code">ui game screen</span>]</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 0 <span class="string">"Sorry, better luck next time."</span></span>)</span>
|
|
<span class="paren2">(<span class="code">s/put-string screen 0 1 <span class="string">"Press escape to exit, anything else to restart."</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> get-viewport-coords <span class="paren2">[<span class="code">game vcols vrows</span>]</span>
|
|
<span class="paren2">(<span class="code"><i><span class="symbol">let</span></i> <span class="paren3">[<span class="code">location <span class="paren4">(<span class="code"><span class="keyword">:location</span> game</span>)</span>
|
|
<span class="paren4">[<span class="code">center-x center-y</span>]</span> location
|
|
|
|
tiles <span class="paren4">(<span class="code"><span class="keyword">:tiles</span> <span class="paren5">(<span class="code"><span class="keyword">:world</span> game</span>)</span></span>)</span>
|
|
|
|
map-rows <span class="paren4">(<span class="code">count tiles</span>)</span>
|
|
map-cols <span class="paren4">(<span class="code">count <span class="paren5">(<span class="code">first tiles</span>)</span></span>)</span>
|
|
|
|
start-x <span class="paren4">(<span class="code">- center-x <span class="paren5">(<span class="code">int <span class="paren6">(<span class="code">/ vcols 2</span>)</span></span>)</span></span>)</span>
|
|
start-x <span class="paren4">(<span class="code">max 0 start-x</span>)</span>
|
|
|
|
start-y <span class="paren4">(<span class="code">- center-y <span class="paren5">(<span class="code">int <span class="paren6">(<span class="code">/ vrows 2</span>)</span></span>)</span></span>)</span>
|
|
start-y <span class="paren4">(<span class="code">max 0 start-y</span>)</span>
|
|
|
|
end-x <span class="paren4">(<span class="code">+ start-x vcols</span>)</span>
|
|
end-x <span class="paren4">(<span class="code">min end-x map-cols</span>)</span>
|
|
|
|
end-y <span class="paren4">(<span class="code">+ start-y vrows</span>)</span>
|
|
end-y <span class="paren4">(<span class="code">min end-y map-rows</span>)</span>
|
|
|
|
start-x <span class="paren4">(<span class="code">- end-x vcols</span>)</span>
|
|
start-y <span class="paren4">(<span class="code">- end-y vrows</span>)</span></span>]</span>
|
|
<span class="paren3">[<span class="code">start-x start-y end-x end-y</span>]</span></span>)</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> draw-crosshairs <span class="paren2">[<span class="code">screen vcols vrows</span>]</span>
|
|
<span class="paren2">(<span class="code"><i><span class="symbol">let</span></i> <span class="paren3">[<span class="code">crosshair-x <span class="paren4">(<span class="code">int <span class="paren5">(<span class="code">/ vcols 2</span>)</span></span>)</span>
|
|
crosshair-y <span class="paren4">(<span class="code">int <span class="paren5">(<span class="code">/ vrows 2</span>)</span></span>)</span></span>]</span>
|
|
<span class="paren3">(<span class="code">s/put-string screen crosshair-x crosshair-y <span class="string">"X"</span> <span class="paren4">{<span class="code"><span class="keyword">:fg</span> <span class="keyword">:red}</span></span>)</span>
|
|
<span class="paren4">(<span class="code">s/move-cursor screen crosshair-x crosshair-y</span>)</span></span>)</span></span>)</span>
|
|
|
|
<span class="paren2">(<span class="code"><i><span class="symbol">defn</span></i> draw-world <span class="paren3">[<span class="code">screen vrows vcols start-x start-y end-x end-y tiles</span>]</span>
|
|
<span class="paren3">(<span class="code">doseq <span class="paren4">[<span class="code"><span class="paren5">[<span class="code">vrow-idx mrow-idx</span>]</span> <span class="paren5">(<span class="code">map vector
|
|
<span class="paren6">(<span class="code">range 0 vrows</span>)</span>
|
|
<span class="paren6">(<span class="code">range start-y end-y</span>)</span></span>)</span>
|
|
<span class="keyword">:let</span> <span class="paren5">[<span class="code">row-tiles <span class="paren6">(<span class="code">subvec <span class="paren1">(<span class="code">tiles mrow-idx</span>)</span> start-x end-x</span>)</span></span>]</span></span>]</span>
|
|
<span class="paren4">(<span class="code">doseq <span class="paren5">[<span class="code">vcol-idx <span class="paren6">(<span class="code">range vcols</span>)</span>
|
|
<span class="keyword">:let</span> <span class="paren6">[<span class="code"><span class="paren1">{<span class="code"><span class="keyword">:keys</span> <span class="paren2">[<span class="code">glyph color</span>]</span></span>}</span> <span class="paren1">(<span class="code">row-tiles vcol-idx</span>)</span></span>]</span></span>]</span>
|
|
<span class="paren5">(<span class="code">s/put-string screen vcol-idx vrow-idx glyph <span class="paren6">{<span class="code"><span class="keyword">:fg</span> color}</span>)</span></span>)</span></span>)</span></span>)</span>
|
|
|
|
<span class="paren3">(<span class="code"><i><span class="symbol">defmethod</span></i> draw-ui <span class="keyword">:play</span> <span class="paren4">[<span class="code">ui game screen</span>]</span>
|
|
<span class="paren4">(<span class="code"><i><span class="symbol">let</span></i> <span class="paren5">[<span class="code">world <span class="paren6">(<span class="code"><span class="keyword">:world</span> game</span>)</span>
|
|
tiles <span class="paren6">(<span class="code"><span class="keyword">:tiles</span> world</span>)</span>
|
|
<span class="paren6">[<span class="code">cols rows</span>]</span> screen-size
|
|
vcols cols
|
|
vrows <span class="paren6">(<span class="code">dec rows</span>)</span>
|
|
<span class="paren6">[<span class="code">start-x start-y end-x end-y</span>]</span> <span class="paren6">(<span class="code">get-viewport-coords game vcols vrows</span>)</span></span>]</span>
|
|
<span class="paren5">(<span class="code">draw-world screen vrows vcols start-x start-y end-x end-y tiles</span>)</span>
|
|
<span class="paren5">(<span class="code">draw-crosshairs screen vcols vrows</span>)</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren3">(<span class="code"><i><span class="symbol">defn</span></i> draw-game <span class="paren4">[<span class="code">game screen</span>]</span>
|
|
<span class="paren4">(<span class="code">clear-screen screen</span>)</span>
|
|
<span class="paren4">(<span class="code">doseq <span class="paren5">[<span class="code">ui <span class="paren6">(<span class="code"><span class="keyword">:uis</span> game</span>)</span></span>]</span>
|
|
<span class="paren5">(<span class="code">draw-ui ui game screen</span>)</span></span>)</span>
|
|
<span class="paren4">(<span class="code">s/redraw screen</span>)</span></span>)</span></span></span></span></span></span></code></pre>
|
|
|
|
<p>And now I need to <code>use</code> the <code>draw-game</code> function back in <code>core.clj</code>:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.core
|
|
<span class="paren2">(<span class="code"><span class="keyword">:use</span> <span class="paren3">[<span class="code">caves.world <span class="keyword">:only</span> <span class="paren4">[<span class="code">random-world smooth-world</span>]</span></span>]</span>
|
|
<span class="paren3">[<span class="code">caves.ui.drawing <span class="keyword">:only</span> <span class="paren4">[<span class="code">draw-game</span>]</span></span>]</span></span>)</span>
|
|
<span class="paren2">(<span class="code"><span class="keyword">:require</span> <span class="paren3">[<span class="code">lanterna.screen <span class="keyword">:as</span> s</span>]</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>The fact that I moved eleven top-level symbols into a new namespace and only had
|
|
to bring one of them back into the original is a pretty clear sign that this
|
|
chunk of code was ready to be moved into its own file.</p>
|
|
|
|
<p>I also did the same for the input processing code, moving it into
|
|
<code>ui/input.clj</code>:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.ui.input
|
|
<span class="paren2">(<span class="code"><span class="keyword">:use</span> <span class="paren3">[<span class="code">caves.world <span class="keyword">:only</span> <span class="paren4">[<span class="code">random-world smooth-world</span>]</span></span>]</span></span>)</span>
|
|
<span class="paren2">(<span class="code"><span class="keyword">:require</span> <span class="paren3">[<span class="code">lanterna.screen <span class="keyword">:as</span> s</span>]</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmulti</span></i> process-input
|
|
<span class="paren2">(<span class="code">fn <span class="paren3">[<span class="code">game input</span>]</span>
|
|
<span class="paren3">(<span class="code"><span class="keyword">:kind</span> <span class="paren4">(<span class="code">last <span class="paren5">(<span class="code"><span class="keyword">:uis</span> game</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> process-input <span class="keyword">:start</span> <span class="paren2">[<span class="code">game input</span>]</span>
|
|
<span class="paren2">(<span class="code">-> game
|
|
<span class="paren3">(<span class="code">assoc <span class="keyword">:world</span> <span class="paren4">(<span class="code">random-world</span>)</span></span>)</span>
|
|
<span class="paren3">(<span class="code">assoc <span class="keyword">:uis</span> <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">->UI <span class="keyword">:play</span></span>)</span></span>]</span></span>)</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> move <span class="paren2">[<span class="code"><span class="paren3">[<span class="code">x y</span>]</span> <span class="paren3">[<span class="code">dx dy</span>]</span></span>]</span>
|
|
<span class="paren2">[<span class="code"><span class="paren3">(<span class="code">+ x dx</span>)</span> <span class="paren3">(<span class="code">+ y dy</span>)</span></span>]</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> process-input <span class="keyword">:play</span> <span class="paren2">[<span class="code">game input</span>]</span>
|
|
<span class="paren2">(<span class="code">case input
|
|
<span class="keyword">:enter</span> <span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">->UI <span class="keyword">:win</span></span>)</span></span>]</span></span>)</span>
|
|
<span class="keyword">:backspace</span> <span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">->UI <span class="keyword">:lose</span></span>)</span></span>]</span></span>)</span>
|
|
\q <span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"></span>]</span></span>)</span>
|
|
|
|
\s <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:world</span></span>]</span> smooth-world</span>)</span>
|
|
|
|
\h <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">-1 0</span>]</span></span>)</span>
|
|
\j <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">0 1</span>]</span></span>)</span>
|
|
\k <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">0 -1</span>]</span></span>)</span>
|
|
\l <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">1 0</span>]</span></span>)</span>
|
|
|
|
\H <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">-5 0</span>]</span></span>)</span>
|
|
\J <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">0 5</span>]</span></span>)</span>
|
|
\K <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">0 -5</span>]</span></span>)</span>
|
|
\L <span class="paren3">(<span class="code">update-in game <span class="paren4">[<span class="code"><span class="keyword">:location</span></span>]</span> move <span class="paren4">[<span class="code">5 0</span>]</span></span>)</span>
|
|
|
|
game</span>)</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> process-input <span class="keyword">:win</span> <span class="paren2">[<span class="code">game input</span>]</span>
|
|
<span class="paren2">(<span class="code"><i><span class="symbol">if</span></i> <span class="paren3">(<span class="code">= input <span class="keyword">:escape</span></span>)</span>
|
|
<span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"></span>]</span></span>)</span>
|
|
<span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">->UI <span class="keyword">:start</span></span>)</span></span>]</span></span>)</span></span>)</span></span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defmethod</span></i> process-input <span class="keyword">:lose</span> <span class="paren2">[<span class="code">game input</span>]</span>
|
|
<span class="paren2">(<span class="code"><i><span class="symbol">if</span></i> <span class="paren3">(<span class="code">= input <span class="keyword">:escape</span></span>)</span>
|
|
<span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"></span>]</span></span>)</span>
|
|
<span class="paren3">(<span class="code">assoc game <span class="keyword">:uis</span> <span class="paren4">[<span class="code"><span class="paren5">(<span class="code">->UI <span class="keyword">:start</span></span>)</span></span>]</span></span>)</span></span>)</span></span>)</span>
|
|
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> get-input <span class="paren2">[<span class="code">game screen</span>]</span>
|
|
<span class="paren2">(<span class="code">assoc game <span class="keyword">:input</span> <span class="paren3">(<span class="code">s/get-key-blocking screen</span>)</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>This isn't quite functional yet, because it needs the <code>->UI</code> factory function,
|
|
which is created by the <code>(defrecord UI [...])</code> that's still in <code>core.clj</code>.
|
|
I can't just <code>use</code> that in this file, because <code>core</code> is going to need to <code>use</code>
|
|
some functions from this, so I'd have circular imports.</p>
|
|
|
|
<p>The solution is to move the <code>(defrecord UI [...])</code> into a separate file.
|
|
I chose to put it in <code>ui/core.clj</code>:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.ui.core</span>)</span>
|
|
|
|
<span class="paren1">(<span class="code"><i><span class="symbol">defrecord</span></i> UI <span class="paren2">[<span class="code">kind</span>]</span></span>)</span></span></code></pre>
|
|
|
|
<p>And now I can pull its creation function back into the <code>input</code> namespace:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.ui.input
|
|
<span class="paren2">(<span class="code"><span class="keyword">:use</span> <span class="paren3">[<span class="code">caves.world <span class="keyword">:only</span> <span class="paren4">[<span class="code">random-world smooth-world</span>]</span></span>]</span>
|
|
<span class="paren3">[<span class="code">caves.ui.core <span class="keyword">:only</span> <span class="paren4">[<span class="code">->UI</span>]</span></span>]</span></span>)</span>
|
|
<span class="paren2">(<span class="code"><span class="keyword">:require</span> <span class="paren3">[<span class="code">lanterna.screen <span class="keyword">:as</span> s</span>]</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>Finally I can update the <code>ns</code> back in the original <code>core.clj</code> to pull in the
|
|
functions I need, and remove the ones I don't:</p>
|
|
|
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.core
|
|
<span class="paren2">(<span class="code"><span class="keyword">:use</span> <span class="paren3">[<span class="code">caves.ui.core <span class="keyword">:only</span> <span class="paren4">[<span class="code">->UI</span>]</span></span>]</span>
|
|
<span class="paren3">[<span class="code">caves.ui.drawing <span class="keyword">:only</span> <span class="paren4">[<span class="code">draw-game</span>]</span></span>]</span>
|
|
<span class="paren3">[<span class="code">caves.ui.input <span class="keyword">:only</span> <span class="paren4">[<span class="code">get-input process-input</span>]</span></span>]</span></span>)</span>
|
|
<span class="paren2">(<span class="code"><span class="keyword">:require</span> <span class="paren3">[<span class="code">lanterna.screen <span class="keyword">:as</span> s</span>]</span></span>)</span></span>)</span></span></code></pre>
|
|
|
|
<p>Whew!</p>
|
|
|
|
<h2 id="s5-results"><a href="index.html#s5-results">Results</a></h2>
|
|
|
|
<p>That was a lot of shuffling around, but now I've got five separate files, each
|
|
pertaining to one specific thing, instead of one big pile of code.</p>
|
|
|
|
<p>You can view the code <a href="https://github.com/sjl/caves/tree/entry-03-4/src/caves">on GitHub</a> if you want to see the end
|
|
result.</p>
|
|
|
|
<p>Next post I swear I'll add the player so we'll have an actual game!</p>
|
|
</article></main><hr class='main-separator' /><footer><nav><a href='https://github.com/sjl/'>GitHub</a> ・ <a href='https://twitter.com/stevelosh/'>Twitter</a> ・ <a href='https://instagram.com/thirtytwobirds/'>Instagram</a> ・ <a href='https://hg.stevelosh.com/.plan/'>.plan</a></nav></footer></body></html> |