Take the 2-minute tour ×

What would be the equivalent of this Python code:

class Player:
    def __init__(self): 
        self.hp = 10
        self.pos = [0,0,0]
        self.items = []
    def damage(self,dmg):
        self.hp -= dmg

player = Player()
player.pos[0] += 5

print player.hp, player.pos, player.items
>> 3 [5,0,0] ["banana"]

In Clojure (or other Lisps)?

share|improve this question

closed as not a real question by Devin Jeanpierre, Óscar López, Rainer Joswig, casperOne Jun 29 '12 at 16:33


no, I just want to see how Lisp deal with this. I've tried: readed some chapters of Practical CL; it seemed overly complicated or I was getting if it was the same. On Clojure I didn't understand what he was doing with the struct-map, and later on with the dispatch function thing. I'm not sure which of those (or other feature) would be used in this case, thus, why I'm asking. –  Viclib Jun 26 '12 at 22:10
rosettacode.org/wiki/Rosetta_Code has small examples for pretty much any language while you wont find a 1 to 1 for your question it will probably show you the way –  Joran Beasley Jun 26 '12 at 22:14
Thank you for pointing the mistakes; I haven't tested the code as it is just a conceptual example and the numbers are not the point. I think you are missing the motivation of down-voting, though. There are many reasons for down-voting, such as it not being a real question. But lack of effort from the author (if this was the case) is not a good reason simply because the question can still help many people that have the same doubt. There are much more people consulting past answers than people asking new questions. –  Viclib Jun 26 '12 at 23:01
@Dokkat if you'd like to return the favor, it's easy - just accept one of the answers –  Benjamin Cox Jun 27 '12 at 18:23
"I always accept an answer"... for some definition of "always", specifically 61% of the time. –  Benjamin Cox Jun 27 '12 at 19:51

4 Answers 4

In Common Lisp:

(defclass player ()
  ((hp :accessor hp :initform 10)
   (pos :accessor pos :initform (list 0 0 0))
   (items :accessor items :initform nil)))

(defmethod damage ((a-player player) damage)
  (decf (hp a-player) damage))

In the REPL

; compiling (DEFCLASS PLAYER ...)
; compiling (DEFMETHOD DAMAGE ...)
CL-USER> (defparameter *player* (make-instance 'player))

CL-USER> (damage *player* 3)
CL-USER> (incf (car (pos *player*)) 5)
CL-USER> (push :banana (items *player*))
CL-USER> (list (hp *player*) (pos *player*) (items *player*))
(7 (5 0 0) (:BANANA))

Personally, I'd break pos up into separate x, y and z, and probably define some methods to put things into and out of the inventory, just in case I decide to change the representation later.

share|improve this answer
Great answer, thank you! –  Viclib Jun 26 '12 at 23:21
I'd possibly express the position as (vector 0 0 0) and closely investigate if I have a single list that is shared or get new lists for each invocation. I'd possibly go as far as leaving the initial value as nil and create a player-creating function. –  Vatine Jun 27 '12 at 9:24

In Racket:

#lang racket

(define player%
  (class object%
    (init-field [hp 10] [pos '(0 0 0)] [items '()])

    (define/public (damage dmg)
      (set! hp (- hp dmg)))

    (define/public (move dx dy dz)
      (set! pos (list (+ (first pos) dx)
                      (+ (second pos) dy)
                      (+ (third pos) dz))))

    (define/public (add-item item)
      (set! items (cons item items)))


(send* (new player%)
       (damage 3)
       (move 5 0 0)
       (add-item "banana"))

You might want to program in a more functional style if you're using Racket, in which case you can write the methods like this to avoid mutation:

(define/public (damage dmg)
  (new this% [hp (- hp dmg)] [pos pos] [items items]))
share|improve this answer
Thank you, but I accidentally downvoted your answer. Stack Overflow is not allowing me to change it: i.imgur.com/X2U1x.png –  Viclib Jun 26 '12 at 23:10
@Dokkat, I edited the answer just to let you fix your accidental down-vote. (All I did was add an extra blank line at the end.) –  steveha Jun 26 '12 at 23:24
@stevaha fixed, thank you. –  Viclib Jun 26 '12 at 23:26

In Clojure:

(def player {
    :hp 10
    :pos [0 0 0]
    :items [] })

(defn damage [player amount]
    (update-in player [:hp] - amount))

(defn move [player direction]
    (update-in player [:pos] #(map + % direction)))

(defn give [player item]
    (update-in player [:items] conj item))

(-> player
    (damage 3)
    (move [5 0 0])
    (give "banana"))

; Output: {:hp 7, :pos (5 0 0), :items ["banana"]}
share|improve this answer
Very simple, thank you! Could I write a macro for the (assoc player :attr (conj (player :attr) item)) –  Viclib Jun 26 '12 at 23:22
I've edited my answer to use update-in which I think is more idiomatic in this case and also alleviates the need for macros. But of course one could write a macro to shorten things up even more. (But in this case I don't think it's necessary and could even hurt readability) –  Matt Jun 27 '12 at 7:00

In Clojure, you wouldn't normally use a mutable data structure, you'd instead create an immutable piece of data that describes the player's current state. Updates to the player would create a new piece of data that describes the updated state. Matt's answer gives a good example of doing this.

If you wanted to maintain a single "player" identity over time with multiple changes of state, you could do so with an atom, something like this:

(def initial-player-state 
 {:hp 10
  :pos [0 0 0]
  :items []})

(def player (atom initial-player-state))

;; Define some update functions

(defn damage [player dmg]
  (update-in player [:hp] + dmg))

(defn move [player dir]
  (update-in player [:pos] #(vec (map + % dir))))

(defn add-item [player item]

;;  Make some changes

(swap! player move [5 0 0])
(swap! player damage -3)
(swap! player add-item "Apple")

;; view the current player state by dereferencing the atom

=> {:hp 10, :pos [0 0 0], :items ["Apple"]}

Note that in a real game, you might have the entire immutable game state in a single atom, not just the player.

share|improve this answer
What is the @ in @player? –  Viclib Jun 26 '12 at 23:11
And thank you, great answer. I'm getting the atom concept now. –  Viclib Jun 26 '12 at 23:22
@ just gets the current value (state) of the atom, i.e. the player hashmap. if you just do playeryou will get the atom itself, rather than the atom's contents.... –  mikera Jun 27 '12 at 9:45
