3

I’m not advanced Lisper, I’m trying to learn the language. So, I'm trying to write a simple card game engine. The bidding is realized in the following way: players are asked about their bids. If a complete list of players accept the bid, the bidding is closed and the data stored. Otherwise all the necessary data are passed to the recursive call. Data transferred to the next call are the following lists: players, their current billings, a true-false list with an information if the player is active, and the history of the game (all payments).

The problem is that the function doesn’t return values from the recursive call.

The initial input data are:

(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))

The code (without the bodies of the helper functions) looks like that:

(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)))

I suppose I made a stupid mistake but actually I can’t manage it. Please help

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))
8
  • Can you describe the problem a bit more? If I add the RETURN-FROM like in my answer and then run (make-round *players* *billings* *participants* *history*), it prompts for the bids, and once everyone has paid an equal amount it returns. There is no error, and the behaviour seems pretty sane to me, so I'm not sure what the problem is. Commented Apr 17, 2016 at 10:35
  • If I run the program, players are prompted to pay the bids. The required payment is the maximum number in the * billings* list. If none of players raises the required payment, everything is ok. However, raising the payment should cause that now the new maximum is required. It works but the new data are not shown in the result lists. Commented Apr 17, 2016 at 14:33
  • When I run it, it first asks for 100 dollars (since that's what Walter pays by default). If I have Bob raise it to 200, it asks for 200 from everyone. The billings it returns are (200 200 200 200 200 200 200 200), which seems correct to me. The returned history also seems correct: ((100 200 200 200 200 200 150 100) (100 0)). Are these not the results it's supposed to give, and if not, what would the correct output be? Commented Apr 17, 2016 at 14:51
  • 1
    Double check that you added the RETURN-FROM just like in my answer (or copy paste the whole function to make sure). The output I get with the input you gave in your example is: (WALTER ALICE BOB CAROL EVE FRANK OSCAR TRENT) (200 200 200 200 200 200 200 200) (T T T T T T T T) ((100 100 100 100 100 100 150 100) (100 100 100 100 100 100 0)). The game-history and billings seem like what you want unless I'm misunderstanding something. Commented Apr 17, 2016 at 15:38
  • 1
    Yes, now it works. Thank you. I added it in the wrong place, my mistake. I'm sorry for stealing your time. Commented Apr 17, 2016 at 15:41

1 Answer 1

1

Look at the call to MAKE-ROUND and see where it returns its value to by working up: MAKE-ROUND -> WHEN -> COND -> LET -> IF which returns to the loop DO-keyword that discards the value.

To prevent the return value from being discarded, you'll have to do an explicit early return with 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)))

Since the code isn't runnable I haven't checked if the logic actually works, but this solves the problem of not returning the value. I recommend that you refactor the code to be more readable at some point.

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately it didn't help. Below I present the rest of the code:
@Jerzy You should edit the code into your question instead of my answer.
The function is called: (make-round players billings participants history)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.