Python代码的等效物是什么:
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.damage(3)
player.pos[0] += 5
player.items.append("banana")
print player.hp, player.pos, player.items
>> 3 [5,0,0] ["banana"]
在Clojure(或其他Lisps)中?
在 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))
在 REPL 中
; compiling (DEFCLASS PLAYER ...)
; compiling (DEFMETHOD DAMAGE ...)
CL-USER> (defparameter *player* (make-instance 'player))
*PLAYER*
CL-USER> (damage *player* 3)
7
CL-USER> (incf (car (pos *player*)) 5)
5
CL-USER> (push :banana (items *player*))
(:BANANA)
CL-USER> (list (hp *player*) (pos *player*) (items *player*))
(7 (5 0 0) (:BANANA))
CL-USER>
就我个人而言,我会pos
分解为单独的x
,y
和z
,并且可能会定义一些方法来将东西放入和移出库存,以防万一我决定稍后更改表示。
在球拍中:
#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)))
(super-new)))
(send* (new player%)
(damage 3)
(move 5 0 0)
(add-item "banana"))
如果您使用的是 Racket,您可能希望以更实用的风格进行编程,在这种情况下,您可以编写这样的方法来避免突变:
(define/public (damage dmg)
(new this% [hp (- hp dmg)] [pos pos] [items items]))
在 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"]}
在Clojure中,你通常不会使用可变的数据结构,而是创建一个不可变的数据来描述玩家的当前状态。对播放器的更新将创建一段描述更新状态的新数据。马特的回答给出了一个很好的例子。
如果你想随着时间的推移保持一个"玩家"身份,并多次改变状态,你可以使用一个原子来实现,如下所示:
(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]
(update-in player [:items] conj 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
@player
=> {:hp 10, :pos [0 0 0], :items ["Apple"]}
请注意,在实际游戏中,您可能将整个不可变游戏状态放在单个原子中,而不仅仅是玩家。