7975761ec4f3

holy shit a blog post
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sat, 07 Jul 2012 18:00:18 -0400
parents 30148ba51e88
children b174875844e2
branches/tags (none)
files content/blog/2012/07/caves-of-clojure-01.html media/images/blog/2012/07/caves-01-01.png

Changes

--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/blog/2012/07/caves-of-clojure-01.html	Sat Jul 07 18:00:18 2012 -0400
@@ -0,0 +1,166 @@
+    {% extends "_post.html" %}
+
+    {% hyde
+        title: "The Caves of Clojure: Part 1"
+        snip: "Getting a Roguelike up and running."
+        created: 2012-07-07 17:00:00
+        flattr: true
+    %}
+
+{% block article %}
+
+Lately I've had an urge to start playing a few games again, namely [Nethack][]
+and [Dwarf Fortress][] (the latter being triggered by [this book][df-book]).
+Aside from being incredibly fun, they also made me want to play around with
+writing a [roguelike][] game of my own.
+
+[Nethack]: http://www.nethack.org/
+[Dwarf Fortress]: http://www.bay12games.com/dwarves/
+[df-book]: 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
+[roguelike]: https://en.wikipedia.org/wiki/Roguelike
+
+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).
+
+I've had the idea of writing a few roguelike games for a while, but the other
+day I stumbled on [Trystan Spangler's blog][trystan] and his [series of
+articles][trystan-tut] that walk through writing a roguelike game in Java.
+
+[trystan]: http://trystans.blogspot.com/
+[trystan-tut]: http://trystans.blogspot.com/2011/08/roguelike-tutorial-01-java-eclipse.html
+
+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.
+
+I'll assume you know Clojure during this series and won't be explaining every
+single thing.
+
+If you want to follow along, the code for this series is [on Bitbucket][bb] and
+[on GitHub][gh].  There are tags like `entry-01` in the repo which you can
+update to and see the code as it stood at the end of that entry.
+
+[bb]: http://bitbucket.org/sjl/caves/
+[gh]: http://github.com/sjl/caves/
+
+Let's jump in.  This entry corresponds to [post one in Trystan's
+tutorial][trystan-tut].
+
+[TOC]
+
+Summary
+-------
+
+The first thing to do is to bootstrap an environment for development.  I'll be
+using Clojure 1.4, Leiningen 2, and [clojure-lanterna][] 0.9.0.
+
+Trystan used Eclipse but I'll be using Vim and my fork of SLIMV.
+
+[clojure-lanterna]: http://sjl.bitbucket.org/clojure-lanterna/
+
+project.clj
+-----------
+
+I'm starting with a fairly simple `project.clj` file:
+
+    :::clojure
+    (defproject caves "0.1.0-SNAPSHOT"
+      :description "The Caves of Clojure"
+      :url "http://stevelosh.com/blog/2012/07/caves-of-clojure-01/"
+      :license {:name "MIT/X11"}
+      :dependencies [[org.clojure/clojure "1.4.0"]
+                     [clojure-lanterna "0.9.0"]]
+      :main caves.core)
+
+Nothing particularly crazy here.
+
+clojure-lanterna
+----------------
+
+Trystan used his own library called AsciiPanel to handle the drawing of
+characters to the screen.  I'm going to use my own library [clojure-lanterna][],
+which is a wrapper around the [Lanterna][] Java library.
+
+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.
+
+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.
+
+[Lanterna]: https://code.google.com/p/lanterna/
+
+core.clj
+--------
+
+The full `core.clj` file I came up with was this:
+
+    :::clojure
+    (ns caves.core
+      (:require [lanterna.screen :as s]))
+
+
+    (defn main [screen-type]
+      (let [screen (s/get-screen screen-type)]
+        (s/in-screen screen
+                     (s/put-string screen 0 0 "Welcome to the Caves of Clojure!")
+                     (s/put-string screen 0 1 "Press any key to exit...")
+                     (s/redraw screen)
+                     (s/get-key-blocking screen))))
+
+
+    (defn -main [& args]
+      (let [args (set args)
+            screen-type (cond
+                          (args ":swing") :swing
+                          (args ":text")  :text
+                          :else           :auto)]
+        (main screen-type)))
+
+We're very much just bootstrapping things for now.  The `-main` function parses
+the command line arguments to figure out what type of terminal we should use,
+and then passes that along to `main`.
+
+For now, `main` simply:
+
+* Gets an appropriately-typed terminal.
+* Outputs a simple message.
+* Redraws the screen (clojure-lanterna's screen layer buffers output until you
+  tell it to redraw).
+* Waits for the user to press a key.
+* Exits.
+
+I chose to split the meat of the setup into a `main` function instead of just
+putting everything in `-main` because that will make it easy for me to work
+through Swank instead of the command line as we'll see in a moment.
+
+Running
+-------
+
+There are two main ways to actually make this thing work.
+
+First, we can run it as a standalone program with `lein trampoline run` at the
+command line.  I can pass a parameter to specify what type of terminal to use,
+like `lein trampoline run :swing`.
+
+We can also run it from a REPL, or a SLIME/Swank environment by simply
+evaluating `(main :swing)` in the namespace.  This is why I split out everything
+but the command line argument parsing into a separate function.
+
+Either way, once you run it you get something like this:
+
+![Screenshot](/media/images{{ parent_url }}/caves-01-01.png)
+
+This is the Swing terminal which I happened to start from swank.  Press a key
+and it will go away.
+
+It doesn't look like much, but it's a [black triangle][].  In the next entry
+we'll start doing more interesting things.
+
+[black triangle]: http://rampantgames.com/blog/2004/10/black-triangle.html
+
+{% endblock article %}
Binary file media/images/blog/2012/07/caves-01-01.png has changed