2

I'd like break out of the below loop and return the best-min-move when line 10 evaluates to true. I've looked at the output with print statements and when line 10 does evaluate to true, it finds the data that I'm looking for but continues to recur. In Clojure is there a way to stop the loop when a statement evaluates to true? Or should I be using something other than a loop recur?

(defn minimax [board max-mark min-mark depth best-score] 
  (loop [board board
     max-mark max-mark
     min-mark min-mark
     depth depth
     best-score best-score]
  (if (= best-score (best-min-score board max-mark min-mark depth))
   (best-max-move board max-mark min-mark depth)                     
   (do                                                               
      (if (= best-score (best-min-score board min-mark max-mark depth))
       (best-min-move board min-mark max-mark depth)              
       (recur 
         (b/make-move-on board (remaining-scores board max-mark min-mark depth) max-mark)                
           min-mark 
           max-mark 
           (inc depth) 
           (dec best-score)))))))
6
  • Your code as it is only recurs when the second if is false. Commented Oct 16, 2014 at 19:12
  • Can you elaborate? When the second if is true its not returning the value (best-min-move board min-mark max-mark depth). It continues to score moves, which leads me to believe that it is recurring. Commented Oct 16, 2014 at 19:16
  • 1
    How do you know that it's recurring? Are you claiming that if doesn't work as it should? If your condition is true, your if evaluates to the first s-expression of the two. If that is the code you're executing, it can't recur unless the condition is false. Commented Oct 16, 2014 at 22:55
  • Thanks for your feedback. It turns out that its one of my private methods that is causing the problem. Commented Oct 17, 2014 at 4:18
  • Does make-move-on call minimax? Is it possible that what you're taking to be looping within one instance of minimax involves a different call to minimax? It would be a good idea to double-check that best-min-score is working correctly, too. I sometimes discover that I reversed a Boolean test by accident. (Also, it wouldn't hurt to simplify the code--maybe that would make it easier to see what's going wrong. You don't need the do, and you could pull min-mark and max-mark out of the loop parameters by adding a let at the top of the definition of minimax. Maybe use cond.) Commented Oct 17, 2014 at 4:23

1 Answer 1

6

About loop

  • It's not loop that loops: it's recur.
  • loop is a let that forms a recur point.
  • You don't and can't break out of a loop: recur breaks you into one.

loop is equivalent to setting up and calling an anonymous function. For example

(loop [n 5, s "Hello, world!"]
  (if (zero? n)
    (first s)
    (recur (dec n) (rest s))))

... is equivalent to

((fn [n s]
  (if (zero? n)
    (first s)
    (recur (dec n) (rest s))))
 5 "Hello, world!")

With some loss of performance, loop could have been written as a macro that carries out the above transformation.


As for your code:

There are six undefined functions here. To clear compilation, we

(declare best-min-score 
         best-max-move
         best-min-move
         best-max-move
         make-move-on
         remaining-scores)

There are also two redundant forms. These do no active harm but do obscure the code.

  • The loop is not needed: the function itself is a suitable target for recur.
  • The do does nothing: it encloses a single form.

Your function reduces to

(defn minimax [board max-mark min-mark depth best-score] 
  (if (= best-score (best-min-score board max-mark min-mark depth))
    (best-max-move board max-mark min-mark depth)
    (if (= best-score (best-min-score board min-mark max-mark depth))
      (best-min-move board min-mark max-mark depth)              
      (recur 
       (make-move-on board (remaining-scores board max-mark min-mark depth) max-mark)                
       min-mark 
       max-mark 
       (inc depth) 
       (dec best-score)))))

Whereas any of the undefined functions may be recurring, the best bet is best-min-move.

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

2 Comments

Thanks! I tool your advice and removed the loop. I also abstracted the first if statement into its own function.
@user3245240 If your subsidiary functions are used only locally, You can define them with let or - if they are mutually recursive - letfn. You can sometimes then pick up some of the arguments from the context.

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.