0

我有一个名为 hand 的列表和另一个名为 deck 的列表,这里的主要目标是在我调用函数 draw 时取出列表卡组中的第一张卡(或元素)并将其放入列表手...

> (draw hand deck)
(2 C)
> (draw hand deck)
(2 C) (3 H) 
> (draw hand deck)
(2 C) (3 H) (K D)

但每次我称之为手永远不会改变价值......我不知道有没有像O-Object这样的方法来永久改变手的内容?

我最初定义手是空的,因为玩家没有牌可以开始。

(define hand '())
4

4 回答 4

1

一种功能性解决方案,draw无副作用:

;; Returns a cons whose car will be the new hand and cdr being the
;; rest of the original deck
(define (draw deck hand)
    (if (not (null? deck))
        (cons (cons (car deck) hand) (cdr deck))
        (cons hand ())))

;; Gets the new hand from the cons returned by draw.
(define (hand cards) (car cards))

;; Gets the new deck from the cons returned by draw.
(define (deck cards) (cdr cards))

;; test
(define cards (draw '(1 2 3 4 5) ()))
cards
=> ((1) 2 3 4 5)
(hand cards)
=> (1)
(deck cards)
=> (2 3 4 5)
;; draw again
(set! cards (draw (deck cards) (hand cards)))
cards
=> ((2 1) 3 4 5)
(hand cards)
=> (2 1)
(deck cards)
=> (3 4 5)
于 2010-04-01T04:05:58.957 回答
0

哦,接下来你会发现,从调用函数的人的角度来看,更改函数内部名称所指的列表不会改变名称所指的内容。所以:

(define (foo lst)
  (set! lst '(hi))
  (display "within foo: ")
  (display lst)
  (newline)
  lst)
(define my-list '(hello))
(foo my-list)
(display "after foo: ") 
(display my-list)
(newline)
(set! my-list (foo my-list))
(display "using the result of foo: ")
(display my-list)
(newline)
于 2010-04-01T03:13:31.540 回答
0

您不能更改列表的内容,但可以更改名称所指的列表。所以:

(let ((some-list '("post")))
 (display "initially: ")
 (display some-list)
 (newline)
 (set! some-list (cons "first" some-list))
 (display "added first: ")
 (display some-list)
 (newline)
 (set! some-list '(a completely new list))
 (display "finally: ")
 (display some-list)
 (newline)
 some-list)

现在每个列表 '("post") '("first" "post") 和 '(一个全新的列表) 都是不可更改的("immutable")列表,但名称 some-list 首先指向一个,然后是另一个,然后是第三个。

警告:对于许多问题,您将要避免设置!并尝试以不同的方式思考问题。例如,如果你为你的游戏使用世界和宇宙, http ://pre.plt-scheme.org/plt/doc/teachpack/2htdpuniverse.html 那么你会希望你的更新程序返回一个新的世界状态而不是使用设置!修改旧的。

于 2010-04-01T03:07:50.187 回答
0

Vijay 为 Scheme 提供了最佳解决方案。但是,如果您真的想通过永久更改列表来完成这项工作,则需要使用set-car!and set-cdr!。这在 Scheme 中并不自然,需要一些技巧才能使其工作:

首先定义handdeck

(define hand '(dummy))
(define deck '((2 C) (3 H) (K D)))

hand必须从现有元素开始,以便它有一些现有的列表结构要修改。您不能将set-car!andset-cdr!与 nil ( '()) 一起使用。

现在写draw

(define (draw from to)
  ; push the top element of `from` onto `to`
  (set-cdr! to (copy to))
  (set-car! to (car from))
  ; pop the top element of `from` off
  (set-car! deck (cadr deck))
  (set-cdr! deck (cddr deck)))
; also we need to define copy
(define (copy l)
  (map (lambda (x) x) l))

这意味着您手中的最后一个元素将始终是哑元。最好为初始案例添加检查并覆盖它而不是推送:

(define (draw from to)
  ; push the top element of `from` onto `to` (just overwrite the first time)
  (when (pair? (cdr to))
    (set-cdr! to (copy to)))
  (set-car! to (car from))
  ; pop the top element of `from` off
  (set-car! deck (cadr deck))
  (set-cdr! deck (cddr deck)))

此外,您应该在做任何事情之前检查它from是否为空。

于 2010-04-01T13:57:19.090 回答