common lisp:来自循环的递归调用

时间:2016-04-17 08:18:16

标签: loops recursion common-lisp

我不是先进的Lisper,我正在努力学习这门语言。所以,我试着写一个简单的纸牌游戏引擎。通过以下方式实现竞标:向玩家询问他们的出价。如果完整的玩家列表接受投标,则关闭投标并存储数据。否则,所有必要的数据都将传递给递归调用。传输到下一个呼叫的数据如下: 玩家,他们目前的账单,一个真假名单,如果玩家是活跃的,还有游戏历史记录(所有付款)。

问题是该函数不会从递归调用中返回值。

初始输入数据为:

(defparameter *billings* (list 0 0 0 0 0 0 50 100))
(defparameter *players* '(Alice Bob Carol Eve Frank Oscar Trent Walter))
(defparameter *participants* (list t t t t t t t t))
(defparameter *history* (list))

代码(没有辅助函数的主体)看起来像:

(defun make-round(rel-players rel-billings rel-participants game-history)
(let((max-billing (maxval rel-billings))
        (curr 0))
  (loop 
     for billing in rel-billings
     for player in rel-players
     for participant in rel-participants                
     do (if(not participant) (setf game-history (add2->history 0 game-history (length rel-players)))          
                (let((bid (ask player billing max-billing)))
                    (cond ((not bid)  (set-assoc-list-val player nil rel-players rel-participants)
                                            (setf game-history (add2->history 0 game-history (length rel-players))) )
                            (t      (setf curr  (+ bid billing))
                                    (set-assoc-list-val player curr rel-players rel-billings)
                                    (setf game-history (add2->history bid game-history (length rel-players)))
                                    (when (> curr max-billing)
                                        (make-round   (divide-players (next-player player rel-players) rel-players)
                                                            (divide-players-list (next-player player rel-players) rel-players rel-billings)
                                                            (divide-players-list (next-player player rel-players) rel-players rel-participants)
                                                            game-history)
                                                                    ))))))
        (values rel-players rel-billings rel-participants game-history)))

我想我犯了一个愚蠢的错误,但实际上我无法管理它。请帮忙

input:
(make-round *players* *billings* *participants* *history*)

Player ALICE has paid 0 dollars but 100 is required. Player ALICE has to pay at least 100 dollars
100
Player BOB has paid 0 dollars but 100 is required. Player BOB has to pay at least 100 dollars
100
Player CAROL has paid 0 dollars but 100 is required. Player CAROL has to pay at least 100 dollars
100
Player EVE has paid 0 dollars but 100 is required. Player EVE has to pay at least 100 dollars
100
Player FRANK has paid 0 dollars but 100 is required. Player FRANK has to pay at least 100 dollars
100
Player OSCAR has paid 0 dollars but 100 is required. Player OSCAR has to pay at least 100 dollars
100
Player TRENT has paid 50 dollars but 100 is required. Player TRENT has to pay at least 50 dollars
150
Player WALTER has paid 100 dollars but 200 is required. Player WALTER has to pay at least 100 dollars
100
Player ALICE has paid 100 dollars but 200 is required. Player ALICE has to pay at least 100 dollars
100
Player BOB has paid 100 dollars but 200 is required. Player BOB has to pay at least 100 dollars
100
Player CAROL has paid 100 dollars but 200 is required. Player CAROL has to pay at least 100 dollars
100
Player EVE has paid 100 dollars but 200 is required. Player EVE has to pay at least 100 dollars
100
Player FRANK has paid 100 dollars but 200 is required. Player FRANK has to pay at least 100 dollars
100
Player OSCAR has paid 100 dollars but 200 is required. Player OSCAR has to pay at least 100 dollars
100
Player TRENT has paid 200 dollars but 200 is required. Player TRENT has to pay at least 0 dollars
0
output:
(ALICE BOB CAROL EVE FRANK OSCAR TRENT WALTER) 
(100 100 100 100 100 100 200 100) 
(T T T T T T T T)
((100 100 100 100 100 100 150))

1 个答案:

答案 0 :(得分:1)

查看对MAKE-ROUND的来电,并通过后续工作查看其返回值的位置:MAKE-ROUND - > WHEN - > COND - > LET - > IF返回循环DO - 丢弃该值的关键字。

为了防止丢弃返回值,您必须使用RETURN-FROM明确提前返回。

(defun make-round (rel-players rel-billings rel-participants game-history)
  (let ((max-billing (maxval rel-billings))
        (curr 0))
    (loop 
       for billing in rel-billings
       for player in rel-players
       for participant in rel-participants                
       do (if (not participant)
              (setf game-history (add2->history 0 game-history (length rel-players)))
              (let ((bid (ask player billing max-billing)))
                (cond ((not bid)
                       (set-assoc-list-val player nil rel-players rel-participants)
                       (setf game-history (add2->history 0 game-history (length rel-players))) )
                      (t
                       (setf curr (+ bid billing))
                       (set-assoc-list-val player curr rel-players rel-billings)
                       (setf game-history (add2->history bid game-history (length rel-players)))
                       (when (> curr max-billing)
                         (return-from make-round
                           (make-round (divide-players (next-player player rel-players) rel-players)
                                       (divide-players-list (next-player player rel-players) rel-players rel-billings)
                                       (divide-players-list (next-player player rel-players) rel-players rel-participants)
                                       game-history))))))))
    (values rel-players rel-billings rel-participants game-history)))

由于代码不可运行,我没有检查逻辑是否真的有效,但这解决了不返回值的问题。我建议您重构代码,使其在某些时候更具可读性。