相当于在某些Lisp语言上编写/访问代码的Python哈希


这个

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分解为单独的xyz,并且可能会定义一些方法来将东西放入和移出库存,以防万一我决定稍后更改表示。

在球拍中:

#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"]}

请注意,在实际游戏中,您可能将整个不可变游戏状态放在单个原子中,而不仅仅是玩家。

最新更新