Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C-style encapsulation techniques in Clojure?

Tags:

clojure

I am working on my first (non-trivial) Clojure program I don't really feel comfortable with how I am declaring all my mutable state globally. For example:

(def next-blocks (atom []))
(def num-next-blocks 1)
(def is-game-over (atom false))
(def user-name (atom (str)))
(def hs-xml (atom nil))

Since I use C a lot at work I came up with the idea of using common C-style encapsulation techniques. It typically involves struct object that passed as a first argument to any "member functions" that operate on it. See udev for example.

Applying this to Clojure would result in functions that look like this (untested):

(defstruct gamestate)

(defn game-new []
  (struct-map gamestate
    :level            (atom 0)
    :score            (atom 0)
    ;etc...
    ))

(def game-get-score [game]
    @(game :score))

(defn game-set-score [game new-score]
  (reset! (game :score) new-score))

(defn game-get-level [game]
  @(game :level))

(defn game-inc-level [game]
  (swap! (game :level) inc))

; etc...

I think it would definitely be a step forward to the global defines that I'm using currently.

So is this the recommended way to go? Or is there a more standard Clojure way?

Update

I'm currently using Clojure 1.1.0.

like image 654
StackedCrooked Avatar asked Aug 12 '26 08:08

StackedCrooked


2 Answers

The basic idea of functional programming is that you have very few global variables but mostly local ones (see Rich Hickey's article on state and identity). Writing a game in this paradigm may be challenging, I'd recommend this post on functional programming for games (the examples are in Erlang, though).

I don't know what kind of game you want to implement. Here is a code snippet improv of what I would do with local variables.

(defn play-game [name score blocks]
  (let [level (start-mission (:level score) blocks)]
    (if level
      (assoc score :level level)
      score)))

(defn the-whole-game []
  (let [name (ask-username)
        score (or (load-score name) {:level 0, :score 0}]
    (when-let [new-score (play-game name score [])]
       (save-score name new-score))))

You may want to check out another Tetris clone in clojure, it uses opengl, though.

like image 74
Adam Schmideg Avatar answered Aug 13 '26 21:08

Adam Schmideg


In my Clojure game I'm using a single atom containing a map to store all my mutable game state. This includes certain elements of the user interface state.

This is currently defined as follows:

(def state 
  (atom 
    {:game (gamefactory/make-game)
     :scroll [0 0]
     :mouseover [0 0]
     :command-state nil
     :commands (clojure.lang.PersistentQueue/EMPTY)
     :animations {}
     :player-id nil}))

This model is working very well for me. You can easily access the state elements directly e.g. (:game @state), or alternatively define accessor functions.

like image 45
mikera Avatar answered Aug 13 '26 22:08

mikera



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!