Clojure port of BSD game "worm" - the growing worm game.
Clojure
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
doc
screenshots
src/wormj
target/stale
test/wormj
.gitignore
README.md
project.clj

README.md

wormj

Clojure port of BSD game worm - the growing worm game.

Notice

The game is finished. ooooooo@

Screenshot of wormj

Build & run

  1. Install Leiningen

  2. Run:

     lein deps
    
  3. You can run the application using Leiningen:

     lein run
    

Or you can build an Uberjar and run that:

    lein uberjar
    java -jar wormj-<version>-standalone.jar

Usage

You can run the application without any options, and the game will attempt to run inside a text-based terminal (Unix or Cygwin):

lein run

However, you can specify a terminal in which to run:

lein run -t <terminal>

Terminal options include:

  • auto: attempt to use Swing-based (GUI) environment, otherwise use text-based console
  • swing: use Swing-based (GUI) environment
  • text: use text-based console. Attempts to use unix or cygwin
  • unix
  • cygwin

So the default is the same as:

lein run -t text

But if you would rather launch a Swing-based GUI environment (but fall back on text-based console):

lein run -t auto

API

Let's start by initializing a game, which generates a 12x12 board, along with a worm and an apple.

(require 'wormj.functions 
         'wormj.state
         'wormj.core :reload)

(wormj.state/init-game 12 12)
(wormj.core/print-game)

;   ┌************┐
; 0 *............*
; 1 *............*
; 2 *............*
; 3 *............*
; 4 *............*
; 5 *............*
; 6 *ooooooo@.2..*
; 7 *............*
; 8 *............*
; 9 *............*
; 0 *............*
; 1 *............*
;   └************┘
;    012345678901

A couple notes about print-game:

  • print-game is intended for debugging, but is not used for rendering during game play
  • The output of print-game in this section (which is shown as ; comments below the Clojure code examples) is slightly enhanced for the sake of clarity.

By chance (though you can always override chance), the apple, 2, randomly appears two spaces to the right of the worm.

Note that the default trajectory is :right, so to advance one space closer to the apple, just advance the turn:

(wormj.state/advance-turn)
(wormj.core/print-game)

;   ┌************┐
; 0 *............*
; 1 *............*
; 2 *............*
; 3 *............*
; 4 *............*
; 5 *............*
; 6 *.ooooooo@2..*
; 7 *............*
; 8 *............*
; 9 *............*
; 0 *............*
; 1 *............*
;   └************┘
;    012345678901

And to consume the apple, advance the turn again:

(wormj.state/advance-turn)
(wormj.core/print-game)

;   :grow-count 2
;
;   ┌************┐
; 0 *............*
; 1 *............*
; 2 *............*
; 3 *............*
; 4 *............*
; 5 *............*
; 6 *..ooooooo@..*
; 7 *............*
; 8 *............*
; 9 *............*
; 0 *..........9.*
; 1 *............*
;   └************┘
;    012345678901

Since the worm consumes the apple, two things happen:

  1. A new apple is randomly generated. In this example, an apple 9 appears at the {:x 10 :y 10} position on the board.
  2. The worm will grow to match the nutritional value of the consumed apple. The last apple, 2, had nutritional value of 2, so for the next two turns the worm will grow.

Note that you can determine how many more turns your worm will grow:

(:grow-count @wormj.state/worm)

This turn, our worm will move up. Our worm also grows this turn, and hence its :grow-count is decremented:

(wormj.state/set-trajectory :up)
(wormj.state/advance-turn)
(wormj.core/print-game)

;   :grow-count 1
;
;   ┌************┐
; 0 *............*
; 1 *............*
; 2 *............*
; 3 *............*
; 4 *............*
; 5 *.........@..*
; 6 *..oooooooo..*
; 7 *............*
; 8 *............*
; 9 *............*
; 0 *..........9.*
; 1 *............*
;   └************┘
;    012345678901

Our worm now takes a :right, and grows one last time (until the next apple is consumed):

(wormj.state/set-trajectory :right)
(wormj.state/advance-turn)  
(wormj.core/print-game)

;   :grow-count 0
;
;   ┌************┐
; 0 *............*
; 1 *............*
; 2 *............*
; 3 *............*
; 4 *............*
; 5 *.........o@.*
; 6 *..oooooooo..*
; 7 *............*
; 8 *............*
; 9 *............*
; 0 *..........9.*
; 1 *............*
;   └************┘
;    012345678901

Finally, the worm turns :down. Since it is no longer growing, the worm's tail starts moving again.

(wormj.state/set-trajectory :down)
(wormj.state/advance-turn)  
(wormj.core/print-game)

;   ┌************┐
; 0 *............*
; 1 *............*
; 2 *............*
; 3 *............*
; 4 *............*
; 5 *.........oo.*
; 6 *...ooooooo@.*
; 7 *............*
; 8 *............*
; 9 *............*
; 0 *..........9.*
; 1 *............*
;   └************┘
;    012345678901

Note that this application has three layers:

  1. Functional layer (src/wormj/functions.clj): pure functions.
  2. State layer (src/wormj/state.clj): holds the game state, such as current worm and board. Also holds any impure functions (such as functions with side-effects or random generation).
  3. GUI layer (src/wormj/core.clj): reads input, calls API, and renders output from state. Also provides functionality like game-to-str and print-game for debugging purposes.

For more examples, see associated tests.

History

  • 1.0 (2013/02/18): Game completed.
  • 0.3 (alpha, 2013/02/17): Game functional (including arrow keys, hjkl, and HJKL), though score not reported until game over, and script arguments ignored.
  • 0.2 (2013/02/16): Functional API, but no GUI.
  • 0.1 (2013/02/12): Game is non-functional while working on documentation and infrastructure.

License

Distributed under Eclipse Public License 1.0, which is the same as Clojure.