133 lines
10 KiB
HTML
133 lines
10 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 1 / 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 1</a></h1><p class='date'>Posted on July 7th, 2012.</p><p>Lately I've had an urge to start playing a few games again, namely <a href="http://www.nethack.org/">Nethack</a>
|
||
|
and <a href="http://www.bay12games.com/dwarves/">Dwarf Fortress</a> (the latter being triggered by <a href="http://www.amazon.com/gp/product/1449314945/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=1449314945&linkCode=as2&tag=stelos-20">this book</a>).
|
||
|
Aside from being incredibly fun, they also made me want to play around with
|
||
|
writing a <a href="https://en.wikipedia.org/wiki/Roguelike">roguelike</a> game of my own.</p>
|
||
|
|
||
|
<p>I could write them in Python, but lately I've been falling out of love with the
|
||
|
language. It's a solid workhorse that's not exciting or beautiful to me at all
|
||
|
any more. My affection has shifted more toward Clojure. Despite its Rubyesque
|
||
|
culture of brokenness, rampant lack of documentation, and warty JVM interop it's
|
||
|
still a wonderful language that's captured me (for now).</p>
|
||
|
|
||
|
<p>I've had the idea of writing a few roguelike games for a while, but the other
|
||
|
day I stumbled on <a href="http://trystans.blogspot.com/">Trystan Spangler's blog</a> and his <a href="http://trystans.blogspot.com/2011/08/roguelike-tutorial-01-java-eclipse.html">series of
|
||
|
articles</a> that walk through writing a roguelike game in Java.</p>
|
||
|
|
||
|
<p>I'm going to do a series of blog posts, each corresponding roughly to one of
|
||
|
Trystan's posts, as I work my way through writing a roguelike in Clojure. I may
|
||
|
or may not get all of the way through his twenty-post series. We'll see.</p>
|
||
|
|
||
|
<p>I'll assume you know Clojure during this series and won't be explaining every
|
||
|
single thing.</p>
|
||
|
|
||
|
<p>If you want to follow along, the code for this series is <a href="http://bitbucket.org/sjl/caves/">on Bitbucket</a> and
|
||
|
<a href="http://github.com/sjl/caves/">on GitHub</a>. There are tags like <code>entry-01</code> in the repo which you can
|
||
|
update to and see the code as it stood at the end of that entry.</p>
|
||
|
|
||
|
<p>Let's jump in. This entry corresponds to <a href="http://trystans.blogspot.com/2011/08/roguelike-tutorial-01-java-eclipse.html">post one in Trystan's
|
||
|
tutorial</a>.</p>
|
||
|
|
||
|
<ol class="table-of-contents"><li><a href="index.html#s1-summary">Summary</a></li><li><a href="index.html#s2-project-clj">project.clj</a></li><li><a href="index.html#s3-clojure-lanterna">clojure-lanterna</a></li><li><a href="index.html#s4-core-clj">core.clj</a></li><li><a href="index.html#s5-running">Running</a></li></ol>
|
||
|
|
||
|
<h2 id="s1-summary"><a href="index.html#s1-summary">Summary</a></h2>
|
||
|
|
||
|
<p>The first thing to do is to bootstrap an environment for development. I'll be
|
||
|
using Clojure 1.4, Leiningen 2, and <a href="https://sjl.bitbucket.io/clojure-lanterna/">clojure-lanterna</a> 0.9.0.</p>
|
||
|
|
||
|
<p>Trystan used Eclipse but I'll be using Vim and my fork of SLIMV.</p>
|
||
|
|
||
|
<h2 id="s2-project-clj"><a href="index.html#s2-project-clj">project.clj</a></h2>
|
||
|
|
||
|
<p>I'm starting with a fairly simple <code>project.clj</code> file:</p>
|
||
|
|
||
|
<pre><code><span class="code"><span class="paren1">(<span class="code"><i><span class="symbol">defproject</span></i> caves <span class="string">"0.1.0-SNAPSHOT"</span>
|
||
|
<span class="keyword">:description</span> <span class="string">"The Caves of Clojure"</span>
|
||
|
<span class="keyword">:url</span> <span class="string">"http://stevelosh.com/blog/2012/07/caves-of-clojure-01/"</span>
|
||
|
<span class="keyword">:license</span> <span class="paren2">{<span class="code"><span class="keyword">:name</span> <span class="string">"MIT/X11"</span></span>}</span>
|
||
|
<span class="keyword">:dependencies</span> <span class="paren2">[<span class="code"><span class="paren3">[<span class="code">org.clojure/clojure <span class="string">"1.4.0"</span></span>]</span>
|
||
|
<span class="paren3">[<span class="code">clojure-lanterna <span class="string">"0.9.0"</span></span>]</span></span>]</span>
|
||
|
<span class="keyword">:main</span> caves.core</span>)</span></span></code></pre>
|
||
|
|
||
|
<p>Nothing particularly crazy here.</p>
|
||
|
|
||
|
<h2 id="s3-clojure-lanterna"><a href="index.html#s3-clojure-lanterna">clojure-lanterna</a></h2>
|
||
|
|
||
|
<p>Trystan used his own library called AsciiPanel to handle the drawing of
|
||
|
characters to the screen. I'm going to use my own library <a href="https://sjl.bitbucket.io/clojure-lanterna/">clojure-lanterna</a>,
|
||
|
which is a wrapper around the <a href="https://code.google.com/p/lanterna/">Lanterna</a> Java library.</p>
|
||
|
|
||
|
<p>I chose Lanterna because it supports drawing to a Swing-based "terminal" and to
|
||
|
the actual console. But unlike some other libraries, it doesn't actually link
|
||
|
against native code (it's pure Java) so it's more portable.</p>
|
||
|
|
||
|
<p>Being able to output to either a console or a GUI means that I can develop
|
||
|
through Swank really easily with the Swing terminal, but actuall play the
|
||
|
finished product in a terminal like God intended.</p>
|
||
|
|
||
|
<h2 id="s4-core-clj"><a href="index.html#s4-core-clj">core.clj</a></h2>
|
||
|
|
||
|
<p>The full <code>core.clj</code> file I came up with was this:</p>
|
||
|
|
||
|
<pre><code><span class="code"><span class="paren1">(<span class="code">ns caves.core
|
||
|
<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">defn</span></i> main <span class="paren2">[<span class="code">screen-type</span>]</span>
|
||
|
<span class="paren2">(<span class="code"><i><span class="symbol">let</span></i> <span class="paren3">[<span class="code">screen <span class="paren4">(<span class="code">s/get-screen screen-type</span>)</span></span>]</span>
|
||
|
<span class="paren3">(<span class="code">s/in-screen screen
|
||
|
<span class="paren4">(<span class="code">s/put-string screen 0 0 <span class="string">"Welcome to the Caves of Clojure!"</span></span>)</span>
|
||
|
<span class="paren4">(<span class="code">s/put-string screen 0 1 <span class="string">"Press any key to exit..."</span></span>)</span>
|
||
|
<span class="paren4">(<span class="code">s/redraw screen</span>)</span>
|
||
|
<span class="paren4">(<span class="code">s/get-key-blocking screen</span>)</span></span>)</span></span>)</span></span>)</span>
|
||
|
|
||
|
|
||
|
<span class="paren1">(<span class="code"><i><span class="symbol">defn</span></i> -main <span class="paren2">[<span class="code">& args</span>]</span>
|
||
|
<span class="paren2">(<span class="code"><i><span class="symbol">let</span></i> <span class="paren3">[<span class="code">args <span class="paren4">(<span class="code">set args</span>)</span>
|
||
|
screen-type <span class="paren4">(<span class="code"><i><span class="symbol">cond</span></i>
|
||
|
<span class="paren5">(<span class="code">args <span class="string">":swing"</span></span>)</span> <span class="keyword">:swing</span>
|
||
|
<span class="paren5">(<span class="code">args <span class="string">":text"</span></span>)</span> <span class="keyword">:text</span>
|
||
|
<span class="keyword">:else</span> <span class="keyword">:auto</span></span>)</span></span>]</span>
|
||
|
<span class="paren3">(<span class="code">main screen-type</span>)</span></span>)</span></span>)</span></span></code></pre>
|
||
|
|
||
|
<p>We're very much just bootstrapping things for now. The <code>-main</code> function parses
|
||
|
the command line arguments to figure out what type of terminal we should use,
|
||
|
and then passes that along to <code>main</code>.</p>
|
||
|
|
||
|
<p>For now, <code>main</code> simply:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li>Gets an appropriately-typed terminal.</li>
|
||
|
<li>Outputs a simple message.</li>
|
||
|
<li>Redraws the screen (clojure-lanterna's screen layer buffers output until you
|
||
|
tell it to redraw).</li>
|
||
|
<li>Waits for the user to press a key.</li>
|
||
|
<li>Exits.</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>I chose to split the meat of the setup into a <code>main</code> function instead of just
|
||
|
putting everything in <code>-main</code> because that will make it easy for me to work
|
||
|
through Swank instead of the command line as we'll see in a moment.</p>
|
||
|
|
||
|
<h2 id="s5-running"><a href="index.html#s5-running">Running</a></h2>
|
||
|
|
||
|
<p>There are two main ways to actually make this thing work.</p>
|
||
|
|
||
|
<p>First, we can run it as a standalone program with <code>lein trampoline run</code> at the
|
||
|
command line. I can pass a parameter to specify what type of terminal to use,
|
||
|
like <code>lein trampoline run :swing</code>.</p>
|
||
|
|
||
|
<p>We can also run it from a REPL, or a SLIME/Swank environment by simply
|
||
|
evaluating <code>(main :swing)</code> in the namespace. This is why I split out everything
|
||
|
but the command line argument parsing into a separate function.</p>
|
||
|
|
||
|
<p>Either way, once you run it you get something like this:</p>
|
||
|
|
||
|
<p><img src="../../../../static/images/blog/2012/07/caves-01-01.png" alt="Screenshot"></p>
|
||
|
|
||
|
<p>This is the Swing terminal which I happened to start from swank. Press a key
|
||
|
and it will go away.</p>
|
||
|
|
||
|
<p>It doesn't look like much, but it's a <a href="http://rampantgames.com/blog/2004/10/black-triangle.html">black triangle</a>. In the next entry
|
||
|
we'll start doing more interesting things.</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>
|